diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000..3c75a1184 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,173 @@ +version: 2.1 + +orbs: + codecov: codecov/codecov@1.0.3 + +jobs: + test: + docker: + - image: circleci/node:11 + working_directory: ~/repo + steps: + - run: + | + sudo wget https://github.com/ethereum/solidity/releases/download/v0.5.8/solc-static-linux -O /usr/local/bin/solc + sudo chmod +x /usr/local/bin/solc + - checkout + - restore_cache: + keys: + - v2-dependencies-{{ checksum "package.json" }} + - v2-dependencies- + - restore_cache: + keys: + - v2-scenario/dependencies-{{ checksum "scenario/package.json" }} + - v2-scenario/dependencies- + - run: yarn install + - run: cd scenario && yarn install + - run: + name: Ganache + command: script/ganache + background: true + - run: | + while ! nc -z localhost 8545; do + sleep 0.1 # wait for ganache to start + done + - save_cache: + paths: + - node_modules + key: v2-dependencies-{{ checksum "package.json" }} + - save_cache: + paths: + - scenario/node_modules + key: v2-scenario-dependencies-{{ checksum "scenario/package.json" }} + - attach_workspace: + at: ~/repo + - run: mkdir ~/junit + - run: TSC_ARGS="" MOCHA_FILE=~/junit/test-results.xml script/test + - store_test_results: + path: ~/junit + - store_artifacts: + path: ~/junit + parallelism: 4 + + mocha_coverage: + parallelism: 5 + docker: + - image: circleci/node:11 + working_directory: ~/repo + steps: + - checkout + - restore_cache: + keys: + - v2-dependencies-{{ checksum "package.json" }} + - v2-dependencies- + - restore_cache: + keys: + - v2-scenario/dependencies-{{ checksum "scenario/package.json" }} + - v2-scenario/dependencies- + - run: yarn install + - run: cd scenario && yarn install + - run: + name: Ganache + command: script/ganache-coverage + background: true + - save_cache: + paths: + - node_modules + key: v2-dependencies-{{ checksum "package.json" }} + - save_cache: + paths: + - scenario/node_modules + key: v2-scenario-dependencies-{{ checksum "scenario/package.json" }} + - attach_workspace: + at: ~/repo + - run: + command: yarn run coverage mocha + no_output_timeout: 20m + - store_artifacts: + path: ~/repo/coverage.json + destination: coverage.json + - store_artifacts: + path: ~/repo/coverage + destination: coverage + - codecov/upload + + scenario_coverage: + docker: + - image: circleci/node:11 + working_directory: ~/repo + steps: + - run: + | + sudo wget https://github.com/ethereum/solidity/releases/download/v0.5.8/solc-static-linux -O /usr/local/bin/solc + sudo chmod +x /usr/local/bin/solc + - checkout + - restore_cache: + keys: + - v2-dependencies-{{ checksum "package.json" }} + - v2-dependencies- + - restore_cache: + keys: + - v2-scenario/dependencies-{{ checksum "scenario/package.json" }} + - v2-scenario/dependencies- + - run: yarn install + - run: cd scenario && yarn install + - run: + name: Ganache + command: script/ganache-coverage + background: true + - save_cache: + paths: + - node_modules + key: v2-dependencies-{{ checksum "package.json" }} + - save_cache: + paths: + - scenario/node_modules + key: v2-scenario-dependencies-{{ checksum "scenario/package.json" }} + - attach_workspace: + at: ~/repo + - run: + command: yarn run coverage scenario + no_output_timeout: 20m + - store_artifacts: + path: ~/repo/coverage.json + destination: coverage.json + - store_artifacts: + path: ~/repo/coverage + destination: coverage + - codecov/upload + + lint: + docker: + - image: circleci/node:11 + - image: trufflesuite/ganache-cli:v6.2.5 + working_directory: ~/repo + steps: + - checkout + - restore_cache: + keys: + - v2-dependencies-{{ checksum "package.json" }} + - v2-dependencies- + - run: yarn install + - save_cache: + paths: + - node_modules + key: v2-dependencies-{{ checksum "package.json" }} + - attach_workspace: + at: ~/repo + - run: yarn run lint + +workflows: + version: 2 + build-test-and-deploy: + jobs: + - test + - mocha_coverage: + filters: + branches: + only: /^(master|(.*-cov(er(age)?)?))$/ + - scenario_coverage: + filters: + branches: + only: /^(master|(.*-cov(er(age)?)?))$/ + - lint diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..aff89f66e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +scenario/node_modules +test +!test/contracts +*.DS_Store \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..8f47fc2bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +allFiredEvents +.build-temp +build +build_ +node_modules +.env +coverage/ +coverage.json +coverageEnv/ +formulas/ +networks/test.json +networks/test-abi.json +networks/coverage.json +networks/coverage-abi.json +networks/development.json +networks/development-abi.json +networks/*-contracts.json +networks/*-history +networks/*-settings.json +outputs/ +Reports/ +scTopics +*.DS_Store +test-results.xml +.tsbuilt +yarn-error.log +scenario/build/webpack.js \ No newline at end of file diff --git a/.solcover.js b/.solcover.js new file mode 100644 index 000000000..20908fd23 --- /dev/null +++ b/.solcover.js @@ -0,0 +1,8 @@ +module.exports = { + port: 8555, + norpc: true, + testCommand: process.env['TEST_COMMAND'] || 'NETWORK=coverage script/test', + skipFiles: ['FormalMoneyMarket.sol', 'test_contracts'].concat( + process.env['SKIP_UNITROLLER'] ? ['Unitroller.sol'] : []), + deepSkip: true +}; diff --git a/.soliumignore b/.soliumignore new file mode 100644 index 000000000..8ca588c52 --- /dev/null +++ b/.soliumignore @@ -0,0 +1,2 @@ +node_modules +test/contracts/WBTC.sol diff --git a/.soliumrc.json b/.soliumrc.json new file mode 100644 index 000000000..bbc39e058 --- /dev/null +++ b/.soliumrc.json @@ -0,0 +1,16 @@ +{ + "extends": "solium:recommended", + "plugins": [ + "security" + ], + "rules": { + "quotes": [ + "error", + "double" + ], + "indentation": [ + "error", + 4 + ] + } +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..092304f6a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +FROM mhart/alpine-node:11.10.1 + +RUN apk update && apk add --no-cache --virtual build-dependencies git python g++ make +RUN yarn global add truffle@5.0.30 +RUN yarn global add ganache-cli@6.5.1 +RUN yarn global add typescript + +RUN wget https://github.com/ethereum/solidity/releases/download/v0.5.8/solc-static-linux -O /usr/local/bin/solc && \ + chmod +x /usr/local/bin/solc + +RUN mkdir -p /deploy/compound-protocol/scenario +WORKDIR /deploy/compound-protocol + +# First add deps +ADD ./package.json /deploy/compound-protocol/ +ADD ./yarn.lock /deploy/compound-protocol/ +RUN yarn install +ADD scenario/package.json /deploy/compound-protocol/scenario +ADD scenario/yarn.lock /deploy/compound-protocol/scenario +RUN ls -la /deploy/compound-protocol +RUN ls -la /deploy/compound-protocol/scenario +RUN cd /deploy/compound-protocol/scenario && yarn install + +# Then rest of code and build +ADD . /deploy/compound-protocol + +RUN truffle compile + +RUN apk del build-dependencies +RUN yarn cache clean + +CMD while :; do sleep 2073600; done diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..50db18e9d --- /dev/null +++ b/LICENSE @@ -0,0 +1,5 @@ +The software and documentation available in this repository (the "Software") is protected by copyright law and accessible pursuant to the license set forth below. Copyright © 2019 Compound Labs, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person or organization obtaining the Software (the “Licensee”) to privately study, review, and analyze the Software. Licensee shall not use the Software for any other purpose. Licensee shall not modify, transfer, assign, share, or sub-license the Software or any derivative works of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..46a3465a9 --- /dev/null +++ b/README.md @@ -0,0 +1,182 @@ +[![CircleCI](https://circleci.com/gh/compound-finance/compound-protocol.svg?style=svg&circle-token=5ed19932325c559a06f71f87d69012aedd2cf3fb)](https://circleci.com/gh/compound-finance/compound-protocol) [![codecov](https://codecov.io/gh/compound-finance/compound-protocol/branch/master/graph/badge.svg?token=q4UvsvVzOX)](https://codecov.io/gh/compound-finance/compound-protocol) + +Compound Protocol +================= + +The Compound Protocol is an Ethereum smart contract for supplying or borrowing assets. Through the cToken contracts, accounts on the blockchain *supply* capital (Ether or ERC-20 tokens) to receive cTokens or *borrow* assets from the protocol (holding other assets as collateral). The Compound cToken contracts track these balances and algorithmically set interest rates for borrowers. + +Before getting started with this repo, please read: + +* The [Compound Whitepaper](https://github.com/compound-finance/compound-protocol/tree/master/docs/CompoundWhitepaper.pdf), describing how Compound works +* The [Compound Protocol Specification](https://github.com/compound-finance/compound-protocol/tree/master/docs/CompoundProtocol.pdf), explaining in plain English how the protocol operates + +For questions about interacting with Compound, please visit [our Discord server](https://compound.finance/discord). + +For security concerns, please visit [https://compound.finance/security](https://compound.finance/security) or email [security@compound.finance](mailto:security@compound.finance). + +Contracts +========= + +We detail a few of the core contracts in the Compound protocol. + +
+
CToken, CErc20 and CEther
+
The Compound cTokens, which are self-contained borrowing and lending contracts. CToken contains the core logic and CErc20 and CEther add public interfaces for Erc20 tokens and ether, respectively. Each CToken is assigned an interest rate and risk model (see InterestRateModel and Comptroller sections), and allows accounts to *mint* (supply capital), *redeem* (withdraw capital), *borrow* and *repay a borrow*. Each CToken is an ERC-20 compliant token where balances represent ownership of the market.
+
+ +
+
Comptroller
+
The risk model contract, which validates permissible user actions and disallows actions if they do not fit certain risk parameters. For instance, the Comptroller enforces that each borrowing user must maintain a sufficient collateral balance across all cTokens.
+
+ +
+
InterestRateModel
+
Contracts which define interest rate models. These models algorithmically determine interest rates based on the current utilization of a given market (that is, how much of the supplied assets are liquid versus borrowed).
+
+ +
+
Careful Math
+
Library for safe math operations.
+
+ +
+
ErrorReporter
+
Library for tracking error codes and failure conditions.
+
+ +
+
Exponential
+
Library for handling fixed-point decimal numbers.
+
+ +
+
SafeToken
+
Library for safely handling Erc20 interaction.
+
+ +
+
WhitePaperInterestRateModel
+
Initial interest rate model, as defined in the Whitepaper. This contract accepts a base rate and slope parameter in its constructor.
+
+ +Installation +------------ +To run compound, pull the repository from GitHub and install its dependencies. You will need [yarn](https://yarnpkg.com/lang/en/docs/install/) or [npm](https://docs.npmjs.com/cli/install) installed. + + git clone https://github.com/compound-finance/compound-protocol + cd compound-protocol + yarn # or `npm install` + +You can then compile and deploy the contracts with: + + yarn run deploy + +Note: this project does not use truffle migrations. The command above is the best way to deploy contracts. To view the addresses of contracts, please inspect the `networks/development.json` file that is produced as an artifact of that command. + +Console +------- + +After you deploy, as above, you can run a truffle console with the following command: + + yarn run console + +This command will create a truffle-like build directory and start a truffle console, thus you can then run: + + truffle(rinkeby)> cDAI.deployed().then((cdai) => cdai.borrowRatePerBlock.call()) + + +You can also specify a network (rinkeby, ropsten, kovan, goerli or mainnet): + + yarn run console rinkeby + +REPL +---- + +The Compound Protocol has a simple scenario evaluation tool to test and evaluate scenarios which could occur on the blockchain. This is primarily used for constructing high-level integration tests. The tool also has a REPL to interact with local the Compound Protocol (similar to `truffle console`). + + yarn run repl + + > Read CToken cBAT Address + Command: Read CToken cBAT Address + AddressV + +You can read more about the scenario runner in the [Scenario Docs](https://github.com/compound-finance/compound-protocol/tree/master/scenario/SCENARIO.md) on steps for using the repl. + +Deployment +---------- + +The easiest way to deploy some Erc20 tokens, cTokens and a Comptroller is through scenario scripts. + + # run ganache locally + script/ganache # or `ganache-cli` + + # ensure development files don't exist as + # new ganache instances invalidate old deployed contracts + rm networks/development* + + # run deployment script + yarn run deploy -v + +After that, you'll have a full set of contracts deployed locally. Look in `networks/development.json` for the addresses for those deployed contracts. You can use the `yarn run console` command above to interact with the contracts (or the scenario REPL, if you prefer). + +Testing +------- +Mocha contract tests are defined under the [test directory](https://github.com/compound-finance/compound-protocol/tree/master/test). To run the tests run: + + yarn run test + +or with inspection (visit chrome://inspect) and look for a remote target after running: + + node --inspect node_modules/truffle-core/cli.js test + +Assertions used in our tests are provided by [ChaiJS](http://chaijs.com). + +Integration Specs +----------------- + +There are additional tests under the [spec/scenario](https://github.com/compound-finance/compound-protocol/tree/master/spec/scenario) folder. These are high-level integration tests based on the scenario runner depicted above. The aim of these tests is to be highly literate and have high coverage in the interaction of contracts. + +Formal Verification Specs +------------------------- + +The Compound Protocol has a number of formal verification specifications, powered by [Certora](https://www.certora.com/). You can find details in the [spec/formal](https://github.com/compound-finance/compound-protocol/tree/master/spec/formal) folder. The Certora Verification Language (CVL) files included are specifications, which when with the Certora CLI tool, produce formal proofs (or counter-examples) that the code of a given contract exactly matches that specification. + +Code Coverage +------------- +To run code coverage, run: + + scripts/ganache-coverage # run ganache in coverage mode + yarn run coverage + +Linting +------- +To lint the code, run: + + yarn run lint + +Docker +------ + +To run in docker: + + # Build the docker image + docker build -t compound-protocol . + + # Run a shell to the built image + docker run -it compound-protocol /bin/sh + +From within a docker shell, you can interact locally with the protocol via ganache and truffle: + + > ganache-cli & + > yarn run deploy + > yarn run console + truffle(development)> cDAI.deployed().then((contract) => cdai = contract); + truffle(development)> cdai.borrowRatePerBlock.call().then((rate) => rate.toNumber()) + 20 + +Discussion +---------- + +For any concerns with the protocol, visit us on [Discord](https://compound.finance/discord) to discuss. + +_© Copyright 2019, Compound Labs, Inc._ diff --git a/contracts/CErc20.sol b/contracts/CErc20.sol new file mode 100644 index 000000000..b86ce526c --- /dev/null +++ b/contracts/CErc20.sol @@ -0,0 +1,215 @@ +pragma solidity ^0.5.8; + +import "./CToken.sol"; + +/** + * @title Compound's CErc20 Contract + * @notice CTokens which wrap an EIP-20 underlying + * @author Compound + */ +contract CErc20 is CToken { + + /** + * @notice Underlying asset for this CToken + */ + address public underlying; + + /** + * @notice Construct a new money market + * @param underlying_ The address of the underlying asset + * @param comptroller_ The address of the Comptroller + * @param interestRateModel_ The address of the interest rate model + * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 + * @param name_ ERC-20 name of this token + * @param symbol_ ERC-20 symbol of this token + * @param decimals_ ERC-20 decimal precision of this token + */ + constructor(address underlying_, + ComptrollerInterface comptroller_, + InterestRateModel interestRateModel_, + uint initialExchangeRateMantissa_, + string memory name_, + string memory symbol_, + uint decimals_) public + CToken(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_) { + // Set underlying + underlying = underlying_; + EIP20Interface(underlying).totalSupply(); // Sanity check the underlying + } + + /*** User Interface ***/ + + /** + * @notice Sender supplies assets into the market and receives cTokens in exchange + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param mintAmount The amount of the underlying asset to supply + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function mint(uint mintAmount) external returns (uint) { + return mintInternal(mintAmount); + } + + /** + * @notice Sender redeems cTokens in exchange for the underlying asset + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemTokens The number of cTokens to redeem into underlying + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function redeem(uint redeemTokens) external returns (uint) { + return redeemInternal(redeemTokens); + } + + /** + * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemAmount The amount of underlying to redeem + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function redeemUnderlying(uint redeemAmount) external returns (uint) { + return redeemUnderlyingInternal(redeemAmount); + } + + /** + * @notice Sender borrows assets from the protocol to their own address + * @param borrowAmount The amount of the underlying asset to borrow + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function borrow(uint borrowAmount) external returns (uint) { + return borrowInternal(borrowAmount); + } + + /** + * @notice Sender repays their own borrow + * @param repayAmount The amount to repay + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function repayBorrow(uint repayAmount) external returns (uint) { + return repayBorrowInternal(repayAmount); + } + + /** + * @notice Sender repays a borrow belonging to borrower + * @param borrower the account with the debt being payed off + * @param repayAmount The amount to repay + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint) { + return repayBorrowBehalfInternal(borrower, repayAmount); + } + + /** + * @notice The sender liquidates the borrowers collateral. + * The collateral seized is transferred to the liquidator. + * @param borrower The borrower of this cToken to be liquidated + * @param cTokenCollateral The market in which to seize collateral from the borrower + * @param repayAmount The amount of the underlying borrowed asset to repay + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function liquidateBorrow(address borrower, uint repayAmount, CToken cTokenCollateral) external returns (uint) { + return liquidateBorrowInternal(borrower, repayAmount, cTokenCollateral); + } + + /*** Safe Token ***/ + + /** + * @notice Gets balance of this contract in terms of the underlying + * @dev This excludes the value of the current message, if any + * @return The quantity of underlying tokens owned by this contract + */ + function getCashPrior() internal view returns (uint) { + EIP20Interface token = EIP20Interface(underlying); + return token.balanceOf(address(this)); + } + + /** + * @dev Checks whether or not there is sufficient allowance for this contract to move amount from `from` and + * whether or not `from` has a balance of at least `amount`. Does NOT do a transfer. + */ + function checkTransferIn(address from, uint amount) internal view returns (Error) { + EIP20Interface token = EIP20Interface(underlying); + + if (token.allowance(from, address(this)) < amount) { + return Error.TOKEN_INSUFFICIENT_ALLOWANCE; + } + + if (token.balanceOf(from) < amount) { + return Error.TOKEN_INSUFFICIENT_BALANCE; + } + + return Error.NO_ERROR; + } + + /** + * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and returns an explanatory + * error code rather than reverting. If caller has not called `checkTransferIn`, this may revert due to + * insufficient balance or insufficient allowance. If caller has called `checkTransferIn` prior to this call, + * and it returned Error.NO_ERROR, this should not revert in normal conditions. + * + * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. + * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca + */ + function doTransferIn(address from, uint amount) internal returns (Error) { + EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); + bool result; + + token.transferFrom(from, address(this), amount); + + // solium-disable-next-line security/no-inline-assembly + assembly { + switch returndatasize() + case 0 { // This is a non-standard ERC-20 + result := not(0) // set result to true + } + case 32 { // This is a complaint ERC-20 + returndatacopy(0, 0, 32) + result := mload(0) // Set `result = returndata` of external call + } + default { // This is an excessively non-compliant ERC-20, revert. + revert(0, 0) + } + } + + if (!result) { + return Error.TOKEN_TRANSFER_IN_FAILED; + } + + return Error.NO_ERROR; + } + + /** + * @dev Similar to EIP20 transfer, except it handles a False result from `transfer` and returns an explanatory + * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to + * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified + * it is >= amount, this should not revert in normal conditions. + * + * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. + * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca + */ + function doTransferOut(address payable to, uint amount) internal returns (Error) { + EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); + bool result; + + token.transfer(to, amount); + + // solium-disable-next-line security/no-inline-assembly + assembly { + switch returndatasize() + case 0 { // This is a non-standard ERC-20 + result := not(0) // set result to true + } + case 32 { // This is a complaint ERC-20 + returndatacopy(0, 0, 32) + result := mload(0) // Set `result = returndata` of external call + } + default { // This is an excessively non-compliant ERC-20, revert. + revert(0, 0) + } + } + + if (!result) { + return Error.TOKEN_TRANSFER_OUT_FAILED; + } + + return Error.NO_ERROR; + } +} diff --git a/contracts/CEther.sol b/contracts/CEther.sol new file mode 100644 index 000000000..6f5cd09c3 --- /dev/null +++ b/contracts/CEther.sol @@ -0,0 +1,168 @@ +pragma solidity ^0.5.8; + +import "./CToken.sol"; + +/** + * @title Compound's CEther Contract + * @notice CToken which wraps Ether + * @author Compound + */ +contract CEther is CToken { + /** + * @notice Construct a new CEther money market + * @param comptroller_ The address of the Comptroller + * @param interestRateModel_ The address of the interest rate model + * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 + * @param name_ ERC-20 name of this token + * @param symbol_ ERC-20 symbol of this token + * @param decimals_ ERC-20 decimal precision of this token + */ + constructor(ComptrollerInterface comptroller_, + InterestRateModel interestRateModel_, + uint initialExchangeRateMantissa_, + string memory name_, + string memory symbol_, + uint decimals_) public + CToken(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_) {} + + /*** User Interface ***/ + + /** + * @notice Sender supplies assets into the market and receives cTokens in exchange + * @dev Reverts upon any failure + */ + function mint() external payable { + requireNoError(mintInternal(msg.value), "mint failed"); + } + + /** + * @notice Sender redeems cTokens in exchange for the underlying asset + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemTokens The number of cTokens to redeem into underlying + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function redeem(uint redeemTokens) external returns (uint) { + return redeemInternal(redeemTokens); + } + + /** + * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemAmount The amount of underlying to redeem + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function redeemUnderlying(uint redeemAmount) external returns (uint) { + return redeemUnderlyingInternal(redeemAmount); + } + + /** + * @notice Sender borrows assets from the protocol to their own address + * @param borrowAmount The amount of the underlying asset to borrow + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function borrow(uint borrowAmount) external returns (uint) { + return borrowInternal(borrowAmount); + } + + /** + * @notice Sender repays their own borrow + * @dev Reverts upon any failure + */ + function repayBorrow() external payable { + requireNoError(repayBorrowInternal(msg.value), "repayBorrow failed"); + } + + /** + * @notice Sender repays a borrow belonging to borrower + * @dev Reverts upon any failure + * @param borrower the account with the debt being payed off + */ + function repayBorrowBehalf(address borrower) external payable { + requireNoError(repayBorrowBehalfInternal(borrower, msg.value), "repayBorrowBehalf failed"); + } + + /** + * @notice The sender liquidates the borrowers collateral. + * The collateral seized is transferred to the liquidator. + * @dev Reverts upon any failure + * @param borrower The borrower of this cToken to be liquidated + * @param cTokenCollateral The market in which to seize collateral from the borrower + */ + function liquidateBorrow(address borrower, CToken cTokenCollateral) external payable { + requireNoError(liquidateBorrowInternal(borrower, msg.value, cTokenCollateral), "liquidateBorrow failed"); + } + + /** + * @notice Send Ether to CEther to mint + */ + function () external payable { + requireNoError(mintInternal(msg.value), "mint failed"); + } + + /*** Safe Token ***/ + + /** + * @notice Gets balance of this contract in terms of Ether, before this message + * @dev This excludes the value of the current message, if any + * @return The quantity of Ether owned by this contract + */ + function getCashPrior() internal view returns (uint) { + (MathError err, uint startingBalance) = subUInt(address(this).balance, msg.value); + require(err == MathError.NO_ERROR); + return startingBalance; + } + + /** + * @notice Checks whether the requested transfer matches the `msg` + * @dev Does NOT do a transfer + * @param from Address sending the Ether + * @param amount Amount of Ether being sent + * @return Whether or not the transfer checks out + */ + function checkTransferIn(address from, uint amount) internal view returns (Error) { + // Sanity checks + require(msg.sender == from, "sender mismatch"); + require(msg.value == amount, "value mismatch"); + return Error.NO_ERROR; + } + + /** + * @notice Perform the actual transfer in, which is a no-op + * @param from Address sending the Ether + * @param amount Amount of Ether being sent + * @return Success + */ + function doTransferIn(address from, uint amount) internal returns (Error) { + // Sanity checks + require(msg.sender == from, "sender mismatch"); + require(msg.value == amount, "value mismatch"); + return Error.NO_ERROR; + } + + function doTransferOut(address payable to, uint amount) internal returns (Error) { + /* Send the Ether, with minimal gas and revert on failure */ + to.transfer(amount); + return Error.NO_ERROR; + } + + function requireNoError(uint errCode, string memory message) internal pure { + if (errCode == uint(Error.NO_ERROR)) { + return; + } + + bytes memory fullMessage = new bytes(bytes(message).length + 5); + uint i; + + for (i = 0; i < bytes(message).length; i++) { + fullMessage[i] = bytes(message)[i]; + } + + fullMessage[i+0] = byte(uint8(32)); + fullMessage[i+1] = byte(uint8(40)); + fullMessage[i+2] = byte(uint8(48 + ( errCode / 10 ))); + fullMessage[i+3] = byte(uint8(48 + ( errCode % 10 ))); + fullMessage[i+4] = byte(uint8(41)); + + require(errCode == uint(Error.NO_ERROR), string(fullMessage)); + } +} diff --git a/contracts/CToken.sol b/contracts/CToken.sol new file mode 100644 index 000000000..df653280f --- /dev/null +++ b/contracts/CToken.sol @@ -0,0 +1,1572 @@ +pragma solidity ^0.5.8; + +import "./ComptrollerInterface.sol"; +import "./ErrorReporter.sol"; +import "./Exponential.sol"; +import "./EIP20Interface.sol"; +import "./EIP20NonStandardInterface.sol"; +import "./ReentrancyGuard.sol"; +import "./InterestRateModel.sol"; + +/** + * @title Compound's CToken Contract + * @notice Abstract base for CTokens + * @author Compound + */ +contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGuard { + /** + * @notice Indicator that this is a CToken contract (for inspection) + */ + bool public constant isCToken = true; + + /** + * @notice EIP-20 token name for this token + */ + string public name; + + /** + * @notice EIP-20 token symbol for this token + */ + string public symbol; + + /** + * @notice EIP-20 token decimals for this token + */ + uint public decimals; + + /** + * @notice Maximum borrow rate that can ever be applied (.0005% / block) + */ + uint constant borrowRateMaxMantissa = 5e14; + + /** + * @notice Maximum fraction of interest that can be set aside for reserves + */ + uint constant reserveFactorMaxMantissa = 1e18; + + /** + * @notice Administrator for this contract + */ + address payable public admin; + + /** + * @notice Pending administrator for this contract + */ + address payable public pendingAdmin; + + /** + * @notice Contract which oversees inter-cToken operations + */ + ComptrollerInterface public comptroller; + + /** + * @notice Model which tells what the current interest rate should be + */ + InterestRateModel public interestRateModel; + + /** + * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) + */ + uint public initialExchangeRateMantissa; + + /** + * @notice Fraction of interest currently set aside for reserves + */ + uint public reserveFactorMantissa; + + /** + * @notice Block number that interest was last accrued at + */ + uint public accrualBlockNumber; + + /** + * @notice Accumulator of total earned interest since the opening of the market + */ + uint public borrowIndex; + + /** + * @notice Total amount of outstanding borrows of the underlying in this market + */ + uint public totalBorrows; + + /** + * @notice Total amount of reserves of the underlying held in this market + */ + uint public totalReserves; + + /** + * @notice Total number of tokens in circulation + */ + uint256 public totalSupply; + + /** + * @notice Official record of token balances for each account + */ + mapping (address => uint256) accountTokens; + + /** + * @notice Approved token transfer amounts on behalf of others + */ + mapping (address => mapping (address => uint256)) transferAllowances; + + /** + * @notice Container for borrow balance information + * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action + * @member interestIndex Global borrowIndex as of the most recent balance-changing action + */ + struct BorrowSnapshot { + uint principal; + uint interestIndex; + } + + /** + * @notice Mapping of account addresses to outstanding borrow balances + */ + mapping(address => BorrowSnapshot) accountBorrows; + + + /*** Market Events ***/ + + /** + * @notice Event emitted when interest is accrued + */ + event AccrueInterest(uint interestAccumulated, uint borrowIndex, uint totalBorrows); + + /** + * @notice Event emitted when tokens are minted + */ + event Mint(address minter, uint mintAmount, uint mintTokens); + + /** + * @notice Event emitted when tokens are redeemed + */ + event Redeem(address redeemer, uint redeemAmount, uint redeemTokens); + + /** + * @notice Event emitted when underlying is borrowed + */ + event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows); + + /** + * @notice Event emitted when a borrow is repaid + */ + event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows); + + /** + * @notice Event emitted when a borrow is liquidated + */ + event LiquidateBorrow(address liquidator, address borrower, uint repayAmount, address cTokenCollateral, uint seizeTokens); + + + /*** Admin Events ***/ + + /** + * @notice Event emitted when pendingAdmin is changed + */ + event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); + + /** + * @notice Event emitted when pendingAdmin is accepted, which means admin is updated + */ + event NewAdmin(address oldAdmin, address newAdmin); + + /** + * @notice Event emitted when comptroller is changed + */ + event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller); + + /** + * @notice Event emitted when interestRateModel is changed + */ + event NewMarketInterestRateModel(InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel); + + /** + * @notice Event emitted when the reserve factor is changed + */ + event NewReserveFactor(uint oldReserveFactorMantissa, uint newReserveFactorMantissa); + + /** + * @notice Event emitted when the reserves are reduced + */ + event ReservesReduced(address admin, uint reduceAmount, uint newTotalReserves); + + + /** + * @notice Construct a new money market + * @param comptroller_ The address of the Comptroller + * @param interestRateModel_ The address of the interest rate model + * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18 + * @param name_ EIP-20 name of this token + * @param symbol_ EIP-20 symbol of this token + * @param decimals_ EIP-20 decimal precision of this token + */ + constructor(ComptrollerInterface comptroller_, + InterestRateModel interestRateModel_, + uint initialExchangeRateMantissa_, + string memory name_, + string memory symbol_, + uint decimals_) internal { + // Set admin to msg.sender + admin = msg.sender; + + // Set initial exchange rate + initialExchangeRateMantissa = initialExchangeRateMantissa_; + require(initialExchangeRateMantissa > 0, "Initial exchange rate must be greater than zero."); + + // Set the comptroller + uint err = _setComptroller(comptroller_); + require(err == uint(Error.NO_ERROR), "Setting comptroller failed"); + + // Initialize block number and borrow index (block number mocks depend on comptroller being set) + accrualBlockNumber = getBlockNumber(); + borrowIndex = mantissaOne; + + // Set the interest rate model (depends on block number / borrow index) + err = _setInterestRateModelFresh(interestRateModel_); + require(err == uint(Error.NO_ERROR), "Setting interest rate model failed"); + + name = name_; + symbol = symbol_; + decimals = decimals_; + } + + /** + * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` + * @dev Called by both `transfer` and `transferFrom` internally + * @param spender The address of the account performing the transfer + * @param src The address of the source account + * @param dst The address of the destination account + * @param tokens The number of tokens to transfer + * @return Whether or not the transfer succeeded + */ + function transferTokens(address spender, address src, address dst, uint tokens) internal returns (uint) { + /* Fail if transfer not allowed */ + uint allowed = comptroller.transferAllowed(address(this), src, dst, tokens); + if (allowed != 0) { + return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.TRANSFER_COMPTROLLER_REJECTION, allowed); + } + + /* Do not allow self-transfers */ + if (src == dst) { + return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); + } + + /* Get the allowance, infinite for the account owner */ + uint startingAllowance = 0; + if (spender == src) { + startingAllowance = uint(-1); + } else { + startingAllowance = transferAllowances[src][spender]; + } + + /* Do the calculations, checking for {under,over}flow */ + MathError mathErr; + uint allowanceNew; + uint srcTokensNew; + uint dstTokensNew; + + (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); + if (mathErr != MathError.NO_ERROR) { + return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); + } + + (mathErr, srcTokensNew) = subUInt(accountTokens[src], tokens); + if (mathErr != MathError.NO_ERROR) { + return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); + } + + (mathErr, dstTokensNew) = addUInt(accountTokens[dst], tokens); + if (mathErr != MathError.NO_ERROR) { + return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + accountTokens[src] = srcTokensNew; + accountTokens[dst] = dstTokensNew; + + /* Eat some of the allowance (if necessary) */ + if (startingAllowance != uint(-1)) { + transferAllowances[src][spender] = allowanceNew; + } + + /* We emit a Transfer event */ + emit Transfer(src, dst, tokens); + + /* We call the defense hook (which checks for under-collateralization) */ + comptroller.transferVerify(address(this), src, dst, tokens); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Transfer `amount` tokens from `msg.sender` to `dst` + * @param dst The address of the destination account + * @param amount The number of tokens to transfer + * @return Whether or not the transfer succeeded + */ + function transfer(address dst, uint256 amount) external nonReentrant returns (bool) { + return transferTokens(msg.sender, msg.sender, dst, amount) == uint(Error.NO_ERROR); + } + + /** + * @notice Transfer `amount` tokens from `src` to `dst` + * @param src The address of the source account + * @param dst The address of the destination account + * @param amount The number of tokens to transfer + * @return Whether or not the transfer succeeded + */ + function transferFrom(address src, address dst, uint256 amount) external nonReentrant returns (bool) { + return transferTokens(msg.sender, src, dst, amount) == uint(Error.NO_ERROR); + } + + /** + * @notice Approve `spender` to transfer up to `amount` from `src` + * @dev This will overwrite the approval amount for `spender` + * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) + * @param spender The address of the account which may transfer tokens + * @param amount The number of tokens that are approved (-1 means infinite) + * @return Whether or not the approval succeeded + */ + function approve(address spender, uint256 amount) external returns (bool) { + address src = msg.sender; + transferAllowances[src][spender] = amount; + emit Approval(src, spender, amount); + return true; + } + + /** + * @notice Get the current allowance from `owner` for `spender` + * @param owner The address of the account which owns the tokens to be spent + * @param spender The address of the account which may transfer tokens + * @return The number of tokens allowed to be spent (-1 means infinite) + */ + function allowance(address owner, address spender) external view returns (uint256) { + return transferAllowances[owner][spender]; + } + + /** + * @notice Get the token balance of the `owner` + * @param owner The address of the account to query + * @return The number of tokens owned by `owner` + */ + function balanceOf(address owner) external view returns (uint256) { + return accountTokens[owner]; + } + + /** + * @notice Get the underlying balance of the `owner` + * @dev This also accrues interest in a transaction + * @param owner The address of the account to query + * @return The amount of underlying owned by `owner` + */ + function balanceOfUnderlying(address owner) external returns (uint) { + Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()}); + (MathError mErr, uint balance) = mulScalarTruncate(exchangeRate, accountTokens[owner]); + require(mErr == MathError.NO_ERROR); + return balance; + } + + /** + * @notice Get a snapshot of the account's balances, and the cached exchange rate + * @dev This is used by comptroller to more efficiently perform liquidity checks. + * @param account Address of the account to snapshot + * @return (possible error, token balance, borrow balance, exchange rate mantissa) + */ + function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint) { + uint cTokenBalance = accountTokens[account]; + uint borrowBalance; + uint exchangeRateMantissa; + + MathError mErr; + + (mErr, borrowBalance) = borrowBalanceStoredInternal(account); + if (mErr != MathError.NO_ERROR) { + return (uint(Error.MATH_ERROR), 0, 0, 0); + } + + (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); + if (mErr != MathError.NO_ERROR) { + return (uint(Error.MATH_ERROR), 0, 0, 0); + } + + return (uint(Error.NO_ERROR), cTokenBalance, borrowBalance, exchangeRateMantissa); + } + + /** + * @dev Function to simply retrieve block number + * This exists mainly for inheriting test contracts to stub this result. + */ + function getBlockNumber() internal view returns (uint) { + return block.number; + } + + /** + * @notice Returns the current per-block borrow interest rate for this cToken + * @return The borrow interest rate per block, scaled by 1e18 + */ + function borrowRatePerBlock() external view returns (uint) { + (uint opaqueErr, uint borrowRateMantissa) = interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves); + require(opaqueErr == 0, "borrowRatePerBlock: interestRateModel.borrowRate failed"); // semi-opaque + return borrowRateMantissa; + } + + /** + * @notice Returns the current per-block supply interest rate for this cToken + * @return The supply interest rate per block, scaled by 1e18 + */ + function supplyRatePerBlock() external view returns (uint) { + /* We calculate the supply rate: + * underlying = totalSupply × exchangeRate + * borrowsPer = totalBorrows ÷ underlying + * supplyRate = borrowRate × (1-reserveFactor) × borrowsPer + */ + uint exchangeRateMantissa = exchangeRateStored(); + + (uint e0, uint borrowRateMantissa) = interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves); + require(e0 == 0, "supplyRatePerBlock: calculating borrowRate failed"); // semi-opaque + + (MathError e1, Exp memory underlying) = mulScalar(Exp({mantissa: exchangeRateMantissa}), totalSupply); + require(e1 == MathError.NO_ERROR, "supplyRatePerBlock: calculating underlying failed"); + + (MathError e2, Exp memory borrowsPer) = divScalarByExp(totalBorrows, underlying); + require(e2 == MathError.NO_ERROR, "supplyRatePerBlock: calculating borrowsPer failed"); + + (MathError e3, Exp memory oneMinusReserveFactor) = subExp(Exp({mantissa: mantissaOne}), Exp({mantissa: reserveFactorMantissa})); + require(e3 == MathError.NO_ERROR, "supplyRatePerBlock: calculating oneMinusReserveFactor failed"); + + (MathError e4, Exp memory supplyRate) = mulExp3(Exp({mantissa: borrowRateMantissa}), oneMinusReserveFactor, borrowsPer); + require(e4 == MathError.NO_ERROR, "supplyRatePerBlock: calculating supplyRate failed"); + + return supplyRate.mantissa; + } + + /** + * @notice Returns the current total borrows plus accrued interest + * @return The total borrows with interest + */ + function totalBorrowsCurrent() external nonReentrant returns (uint) { + require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed"); + return totalBorrows; + } + + /** + * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex + * @param account The address whose balance should be calculated after updating borrowIndex + * @return The calculated balance + */ + function borrowBalanceCurrent(address account) external nonReentrant returns (uint) { + require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed"); + return borrowBalanceStored(account); + } + + /** + * @notice Return the borrow balance of account based on stored data + * @param account The address whose balance should be calculated + * @return The calculated balance + */ + function borrowBalanceStored(address account) public view returns (uint) { + (MathError err, uint result) = borrowBalanceStoredInternal(account); + require(err == MathError.NO_ERROR, "borrowBalanceStored: borrowBalanceStoredInternal failed"); + return result; + } + + /** + * @notice Return the borrow balance of account based on stored data + * @param account The address whose balance should be calculated + * @return (error code, the calculated balance or 0 if error code is non-zero) + */ + function borrowBalanceStoredInternal(address account) internal view returns (MathError, uint) { + /* Note: we do not assert that the market is up to date */ + MathError mathErr; + uint principalTimesIndex; + uint result; + + /* Get borrowBalance and borrowIndex */ + BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; + + /* If borrowBalance = 0 then borrowIndex is likely also 0. + * Rather than failing the calculation with a division by 0, we immediately return 0 in this case. + */ + if (borrowSnapshot.principal == 0) { + return (MathError.NO_ERROR, 0); + } + + /* Calculate new borrow balance using the interest index: + * recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex + */ + (mathErr, principalTimesIndex) = mulUInt(borrowSnapshot.principal, borrowIndex); + if (mathErr != MathError.NO_ERROR) { + return (mathErr, 0); + } + + (mathErr, result) = divUInt(principalTimesIndex, borrowSnapshot.interestIndex); + if (mathErr != MathError.NO_ERROR) { + return (mathErr, 0); + } + + return (MathError.NO_ERROR, result); + } + + /** + * @notice Accrue interest then return the up-to-date exchange rate + * @return Calculated exchange rate scaled by 1e18 + */ + function exchangeRateCurrent() public nonReentrant returns (uint) { + require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed"); + return exchangeRateStored(); + } + + /** + * @notice Calculates the exchange rate from the underlying to the CToken + * @dev This function does not accrue interest before calculating the exchange rate + * @return Calculated exchange rate scaled by 1e18 + */ + function exchangeRateStored() public view returns (uint) { + (MathError err, uint result) = exchangeRateStoredInternal(); + require(err == MathError.NO_ERROR, "exchangeRateStored: exchangeRateStoredInternal failed"); + return result; + } + + /** + * @notice Calculates the exchange rate from the underlying to the CToken + * @dev This function does not accrue interest before calculating the exchange rate + * @return (error code, calculated exchange rate scaled by 1e18) + */ + function exchangeRateStoredInternal() internal view returns (MathError, uint) { + if (totalSupply == 0) { + /* + * If there are no tokens minted: + * exchangeRate = initialExchangeRate + */ + return (MathError.NO_ERROR, initialExchangeRateMantissa); + } else { + /* + * Otherwise: + * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply + */ + uint totalCash = getCashPrior(); + uint cashPlusBorrowsMinusReserves; + Exp memory exchangeRate; + MathError mathErr; + + (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows, totalReserves); + if (mathErr != MathError.NO_ERROR) { + return (mathErr, 0); + } + + (mathErr, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, totalSupply); + if (mathErr != MathError.NO_ERROR) { + return (mathErr, 0); + } + + return (MathError.NO_ERROR, exchangeRate.mantissa); + } + } + + /** + * @notice Get cash balance of this cToken in the underlying asset + * @return The quantity of underlying asset owned by this contract + */ + function getCash() external view returns (uint) { + return getCashPrior(); + } + + struct AccrueInterestLocalVars { + MathError mathErr; + uint opaqueErr; + uint borrowRateMantissa; + uint currentBlockNumber; + uint blockDelta; + + Exp simpleInterestFactor; + + uint interestAccumulated; + uint totalBorrowsNew; + uint totalReservesNew; + uint borrowIndexNew; + } + + /** + * @notice Applies accrued interest to total borrows and reserves. + * @dev This calculates interest accrued from the last checkpointed block + * up to the current block and writes new checkpoint to storage. + */ + function accrueInterest() public returns (uint) { + AccrueInterestLocalVars memory vars; + + /* Calculate the current borrow interest rate */ + (vars.opaqueErr, vars.borrowRateMantissa) = interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves); + require(vars.borrowRateMantissa <= borrowRateMaxMantissa, "borrow rate is absurdly high"); + if (vars.opaqueErr != 0) { + return failOpaque(Error.INTEREST_RATE_MODEL_ERROR, FailureInfo.ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, vars.opaqueErr); + } + + /* Remember the initial block number */ + vars.currentBlockNumber = getBlockNumber(); + + /* Calculate the number of blocks elapsed since the last accrual */ + (vars.mathErr, vars.blockDelta) = subUInt(vars.currentBlockNumber, accrualBlockNumber); + assert(vars.mathErr == MathError.NO_ERROR); // Block delta should always succeed and if it doesn't, blow up. + + /* + * Calculate the interest accumulated into borrows and reserves and the new index: + * simpleInterestFactor = borrowRate * blockDelta + * interestAccumulated = simpleInterestFactor * totalBorrows + * totalBorrowsNew = interestAccumulated + totalBorrows + * totalReservesNew = interestAccumulated * reserveFactor + totalReserves + * borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex + */ + (vars.mathErr, vars.simpleInterestFactor) = mulScalar(Exp({mantissa: vars.borrowRateMantissa}), vars.blockDelta); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, uint(vars.mathErr)); + } + + (vars.mathErr, vars.interestAccumulated) = mulScalarTruncate(vars.simpleInterestFactor, totalBorrows); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, uint(vars.mathErr)); + } + + (vars.mathErr, vars.totalBorrowsNew) = addUInt(vars.interestAccumulated, totalBorrows); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, uint(vars.mathErr)); + } + + (vars.mathErr, vars.totalReservesNew) = mulScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), vars.interestAccumulated, totalReserves); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, uint(vars.mathErr)); + } + + (vars.mathErr, vars.borrowIndexNew) = mulScalarTruncateAddUInt(vars.simpleInterestFactor, borrowIndex, borrowIndex); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, uint(vars.mathErr)); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* We write the previously calculated values into storage */ + accrualBlockNumber = vars.currentBlockNumber; + borrowIndex = vars.borrowIndexNew; + totalBorrows = vars.totalBorrowsNew; + totalReserves = vars.totalReservesNew; + + /* We emit an AccrueInterest event */ + emit AccrueInterest(vars.interestAccumulated, vars.borrowIndexNew, totalBorrows); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sender supplies assets into the market and receives cTokens in exchange + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param mintAmount The amount of the underlying asset to supply + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function mintInternal(uint mintAmount) internal nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed + return fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED); + } + // mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to + return mintFresh(msg.sender, mintAmount); + } + + struct MintLocalVars { + Error err; + MathError mathErr; + uint exchangeRateMantissa; + uint mintTokens; + uint totalSupplyNew; + uint accountTokensNew; + } + + /** + * @notice User supplies assets into the market and receives cTokens in exchange + * @dev Assumes interest has already been accrued up to the current block + * @param minter The address of the account which is supplying the assets + * @param mintAmount The amount of the underlying asset to supply + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function mintFresh(address minter, uint mintAmount) internal returns (uint) { + /* Fail if mint not allowed */ + uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount); + if (allowed != 0) { + return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.MINT_COMPTROLLER_REJECTION, allowed); + } + + /* Verify market's block number equals current block number */ + if (accrualBlockNumber != getBlockNumber()) { + return fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK); + } + + MintLocalVars memory vars; + + /* Fail if checkTransferIn fails */ + vars.err = checkTransferIn(minter, mintAmount); + if (vars.err != Error.NO_ERROR) { + return fail(vars.err, FailureInfo.MINT_TRANSFER_IN_NOT_POSSIBLE); + } + + /* + * We get the current exchange rate and calculate the number of cTokens to be minted: + * mintTokens = mintAmount / exchangeRate + */ + (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal(); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)); + } + + (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(mintAmount, Exp({mantissa: vars.exchangeRateMantissa})); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, uint(vars.mathErr)); + } + + /* + * We calculate the new total supply of cTokens and minter token balance, checking for overflow: + * totalSupplyNew = totalSupply + mintTokens + * accountTokensNew = accountTokens[minter] + mintTokens + */ + (vars.mathErr, vars.totalSupplyNew) = addUInt(totalSupply, vars.mintTokens); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr)); + } + + (vars.mathErr, vars.accountTokensNew) = addUInt(accountTokens[minter], vars.mintTokens); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* + * We call doTransferIn for the minter and the mintAmount + * Note: The cToken must handle variations between ERC-20 and ETH underlying. + * On success, the cToken holds an additional mintAmount of cash. + * If doTransferIn fails despite the fact we checked pre-conditions, + * we revert because we can't be sure if side effects occurred. + */ + vars.err = doTransferIn(minter, mintAmount); + if (vars.err != Error.NO_ERROR) { + return fail(vars.err, FailureInfo.MINT_TRANSFER_IN_FAILED); + } + + /* We write previously calculated values into storage */ + totalSupply = vars.totalSupplyNew; + accountTokens[minter] = vars.accountTokensNew; + + /* We emit a Mint event, and a Transfer event */ + emit Mint(minter, mintAmount, vars.mintTokens); + emit Transfer(address(this), minter, vars.mintTokens); + + /* We call the defense hook */ + comptroller.mintVerify(address(this), minter, mintAmount, vars.mintTokens); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sender redeems cTokens in exchange for the underlying asset + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemTokens The number of cTokens to redeem into underlying + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function redeemInternal(uint redeemTokens) internal nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed + return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); + } + // redeemFresh emits redeem-specific logs on errors, so we don't need to + return redeemFresh(msg.sender, redeemTokens, 0); + } + + /** + * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset + * @dev Accrues interest whether or not the operation succeeds, unless reverted + * @param redeemAmount The amount of underlying to redeem + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed + return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); + } + // redeemFresh emits redeem-specific logs on errors, so we don't need to + return redeemFresh(msg.sender, 0, redeemAmount); + } + + struct RedeemLocalVars { + Error err; + MathError mathErr; + uint exchangeRateMantissa; + uint redeemTokens; + uint redeemAmount; + uint totalSupplyNew; + uint accountTokensNew; + } + + /** + * @notice User redeems cTokens in exchange for the underlying asset + * @dev Assumes interest has already been accrued up to the current block + * @param redeemer The address of the account which is redeeming the tokens + * @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be zero) + * @param redeemAmountIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be zero) + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal returns (uint) { + require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero"); + + RedeemLocalVars memory vars; + + /* exchangeRate = invoke Exchange Rate Stored() */ + (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal(); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)); + } + + /* If redeemTokensIn > 0: */ + if (redeemTokensIn > 0) { + /* + * We calculate the exchange rate and the amount of underlying to be redeemed: + * redeemTokens = redeemTokensIn + * redeemAmount = redeemTokensIn x exchangeRateCurrent + */ + vars.redeemTokens = redeemTokensIn; + + (vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr)); + } + } else { + /* + * We get the current exchange rate and calculate the amount to be redeemed: + * redeemTokens = redeemAmountIn / exchangeRate + * redeemAmount = redeemAmountIn + */ + + (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa})); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, uint(vars.mathErr)); + } + + vars.redeemAmount = redeemAmountIn; + } + + /* Fail if redeem not allowed */ + uint allowed = comptroller.redeemAllowed(address(this), redeemer, vars.redeemTokens); + if (allowed != 0) { + return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REDEEM_COMPTROLLER_REJECTION, allowed); + } + + /* Verify market's block number equals current block number */ + if (accrualBlockNumber != getBlockNumber()) { + return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDEEM_FRESHNESS_CHECK); + } + + /* + * We calculate the new total supply and redeemer balance, checking for underflow: + * totalSupplyNew = totalSupply - redeemTokens + * accountTokensNew = accountTokens[redeemer] - redeemTokens + */ + (vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply, vars.redeemTokens); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr)); + } + + (vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[redeemer], vars.redeemTokens); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); + } + + /* Fail gracefully if protocol has insufficient cash */ + if (getCashPrior() < vars.redeemAmount) { + return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* + * We invoke doTransferOut for the redeemer and the redeemAmount. + * Note: The cToken must handle variations between ERC-20 and ETH underlying. + * On success, the cToken has redeemAmount less of cash. + * If doTransferOut fails despite the fact we checked pre-conditions, + * we revert because we can't be sure if side effects occurred. + */ + vars.err = doTransferOut(redeemer, vars.redeemAmount); + require(vars.err == Error.NO_ERROR, "redeem transfer out failed"); + + /* We write previously calculated values into storage */ + totalSupply = vars.totalSupplyNew; + accountTokens[redeemer] = vars.accountTokensNew; + + /* We emit a Transfer event, and a Redeem event */ + emit Transfer(redeemer, address(this), vars.redeemTokens); + emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); + + /* We call the defense hook */ + comptroller.redeemVerify(address(this), redeemer, vars.redeemAmount, vars.redeemTokens); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sender borrows assets from the protocol to their own address + * @param borrowAmount The amount of the underlying asset to borrow + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function borrowInternal(uint borrowAmount) internal nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed + return fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); + } + // borrowFresh emits borrow-specific logs on errors, so we don't need to + return borrowFresh(msg.sender, borrowAmount); + } + + struct BorrowLocalVars { + Error err; + MathError mathErr; + uint accountBorrows; + uint accountBorrowsNew; + uint totalBorrowsNew; + } + + /** + * @notice Users borrow assets from the protocol to their own address + * @param borrowAmount The amount of the underlying asset to borrow + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function borrowFresh(address payable borrower, uint borrowAmount) internal returns (uint) { + /* Fail if borrow not allowed */ + uint allowed = comptroller.borrowAllowed(address(this), borrower, borrowAmount); + if (allowed != 0) { + return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.BORROW_COMPTROLLER_REJECTION, allowed); + } + + /* Verify market's block number equals current block number */ + if (accrualBlockNumber != getBlockNumber()) { + return fail(Error.MARKET_NOT_FRESH, FailureInfo.BORROW_FRESHNESS_CHECK); + } + + /* Fail gracefully if protocol has insufficient underlying cash */ + if (getCashPrior() < borrowAmount) { + return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.BORROW_CASH_NOT_AVAILABLE); + } + + BorrowLocalVars memory vars; + + /* + * We calculate the new borrower and total borrow balances, failing on overflow: + * accountBorrowsNew = accountBorrows + borrowAmount + * totalBorrowsNew = totalBorrows + borrowAmount + */ + (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); + } + + (vars.mathErr, vars.accountBorrowsNew) = addUInt(vars.accountBorrows, borrowAmount); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); + } + + (vars.mathErr, vars.totalBorrowsNew) = addUInt(totalBorrows, borrowAmount); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* + * We invoke doTransferOut for the borrower and the borrowAmount. + * Note: The cToken must handle variations between ERC-20 and ETH underlying. + * On success, the cToken borrowAmount less of cash. + * If doTransferOut fails despite the fact we checked pre-conditions, + * we revert because we can't be sure if side effects occurred. + */ + vars.err = doTransferOut(borrower, borrowAmount); + require(vars.err == Error.NO_ERROR, "borrow transfer out failed"); + + /* We write the previously calculated values into storage */ + accountBorrows[borrower].principal = vars.accountBorrowsNew; + accountBorrows[borrower].interestIndex = borrowIndex; + totalBorrows = vars.totalBorrowsNew; + + /* We emit a Borrow event */ + emit Borrow(borrower, borrowAmount, vars.accountBorrowsNew, vars.totalBorrowsNew); + + /* We call the defense hook */ + comptroller.borrowVerify(address(this), borrower, borrowAmount); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sender repays their own borrow + * @param repayAmount The amount to repay + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function repayBorrowInternal(uint repayAmount) internal nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed + return fail(Error(error), FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED); + } + // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to + return repayBorrowFresh(msg.sender, msg.sender, repayAmount); + } + + /** + * @notice Sender repays a borrow belonging to borrower + * @param borrower the account with the debt being payed off + * @param repayAmount The amount to repay + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function repayBorrowBehalfInternal(address borrower, uint repayAmount) internal nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed + return fail(Error(error), FailureInfo.REPAY_BEHALF_ACCRUE_INTEREST_FAILED); + } + // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to + return repayBorrowFresh(msg.sender, borrower, repayAmount); + } + + struct RepayBorrowLocalVars { + Error err; + MathError mathErr; + uint repayAmount; + uint borrowerIndex; + uint accountBorrows; + uint accountBorrowsNew; + uint totalBorrowsNew; + } + + /** + * @notice Borrows are repaid by another user (possibly the borrower). + * @param payer the account paying off the borrow + * @param borrower the account with the debt being payed off + * @param repayAmount the amount of undelrying tokens being returned + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function repayBorrowFresh(address payer, address borrower, uint repayAmount) internal returns (uint) { + /* Fail if repayBorrow not allowed */ + uint allowed = comptroller.repayBorrowAllowed(address(this), payer, borrower, repayAmount); + if (allowed != 0) { + return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, allowed); + } + + /* Verify market's block number equals current block number */ + if (accrualBlockNumber != getBlockNumber()) { + return fail(Error.MARKET_NOT_FRESH, FailureInfo.REPAY_BORROW_FRESHNESS_CHECK); + } + + RepayBorrowLocalVars memory vars; + + /* We remember the original borrowerIndex for verification purposes */ + vars.borrowerIndex = accountBorrows[borrower].interestIndex; + + /* We fetch the amount the borrower owes, with accumulated interest */ + (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); + } + + /* If repayAmount == -1, repayAmount = accountBorrows */ + if (repayAmount == uint(-1)) { + vars.repayAmount = vars.accountBorrows; + } else { + vars.repayAmount = repayAmount; + } + + /* Fail if checkTransferIn fails */ + vars.err = checkTransferIn(payer, vars.repayAmount); + if (vars.err != Error.NO_ERROR) { + return fail(vars.err, FailureInfo.REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE); + } + + /* + * We calculate the new borrower and total borrow balances, failing on underflow: + * accountBorrowsNew = accountBorrows - repayAmount + * totalBorrowsNew = totalBorrows - repayAmount + */ + (vars.mathErr, vars.accountBorrowsNew) = subUInt(vars.accountBorrows, vars.repayAmount); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); + } + + (vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, vars.repayAmount); + if (vars.mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* + * We call doTransferIn for the payer and the repayAmount + * Note: The cToken must handle variations between ERC-20 and ETH underlying. + * On success, the cToken holds an additional repayAmount of cash. + * If doTransferIn fails despite the fact we checked pre-conditions, + * we revert because we can't be sure if side effects occurred. + */ + vars.err = doTransferIn(payer, vars.repayAmount); + require(vars.err == Error.NO_ERROR, "repay borrow transfer in failed"); + + /* We write the previously calculated values into storage */ + accountBorrows[borrower].principal = vars.accountBorrowsNew; + accountBorrows[borrower].interestIndex = borrowIndex; + totalBorrows = vars.totalBorrowsNew; + + /* We emit a RepayBorrow event */ + emit RepayBorrow(payer, borrower, vars.repayAmount, vars.accountBorrowsNew, vars.totalBorrowsNew); + + /* We call the defense hook */ + comptroller.repayBorrowVerify(address(this), payer, borrower, vars.repayAmount, vars.borrowerIndex); + + return uint(Error.NO_ERROR); + } + + /** + * @notice The sender liquidates the borrowers collateral. + * The collateral seized is transferred to the liquidator. + * @param borrower The borrower of this cToken to be liquidated + * @param cTokenCollateral The market in which to seize collateral from the borrower + * @param repayAmount The amount of the underlying borrowed asset to repay + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function liquidateBorrowInternal(address borrower, uint repayAmount, CToken cTokenCollateral) internal nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed + return fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED); + } + + error = cTokenCollateral.accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed + return fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED); + } + + // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to + return liquidateBorrowFresh(msg.sender, borrower, repayAmount, cTokenCollateral); + } + + /** + * @notice The liquidator liquidates the borrowers collateral. + * The collateral seized is transferred to the liquidator. + * @param borrower The borrower of this cToken to be liquidated + * @param liquidator The address repaying the borrow and seizing collateral + * @param cTokenCollateral The market in which to seize collateral from the borrower + * @param repayAmount The amount of the underlying borrowed asset to repay + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function liquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, CToken cTokenCollateral) internal returns (uint) { + /* Fail if liquidate not allowed */ + uint allowed = comptroller.liquidateBorrowAllowed(address(this), address(cTokenCollateral), liquidator, borrower, repayAmount); + if (allowed != 0) { + return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, allowed); + } + + /* Verify market's block number equals current block number */ + if (accrualBlockNumber != getBlockNumber()) { + return fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_FRESHNESS_CHECK); + } + + /* Verify cTokenCollateral market's block number equals current block number */ + if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { + return fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK); + } + + /* Fail if borrower = liquidator */ + if (borrower == liquidator) { + return fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER); + } + + /* Fail if repayAmount = 0 */ + if (repayAmount == 0) { + return fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO); + } + + /* Fail if repayAmount = -1 */ + if (repayAmount == uint(-1)) { + return fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX); + } + + /* We calculate the number of collateral tokens that will be seized */ + (uint amountSeizeError, uint seizeTokens) = comptroller.liquidateCalculateSeizeTokens(address(this), address(cTokenCollateral), repayAmount); + if (amountSeizeError != 0) { + return failOpaque(Error.COMPTROLLER_CALCULATION_ERROR, FailureInfo.LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, amountSeizeError); + } + + /* Fail if seizeTokens > borrower collateral token balance */ + if (seizeTokens > cTokenCollateral.balanceOf(borrower)) { + return fail(Error.TOKEN_INSUFFICIENT_BALANCE, FailureInfo.LIQUIDATE_SEIZE_TOO_MUCH); + } + + /* Fail if repayBorrow fails */ + uint repayBorrowError = repayBorrowFresh(liquidator, borrower, repayAmount); + if (repayBorrowError != uint(Error.NO_ERROR)) { + return fail(Error(repayBorrowError), FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED); + } + + /* Revert if seize tokens fails (since we cannot be sure of side effects) */ + uint seizeError = cTokenCollateral.seize(liquidator, borrower, seizeTokens); + require(seizeError == uint(Error.NO_ERROR), "token seizure failed"); + + /* We emit a LiquidateBorrow event */ + emit LiquidateBorrow(liquidator, borrower, repayAmount, address(cTokenCollateral), seizeTokens); + + /* We call the defense hook */ + comptroller.liquidateBorrowVerify(address(this), address(cTokenCollateral), liquidator, borrower, repayAmount, seizeTokens); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Transfers collateral tokens (this market) to the liquidator. + * @dev Will fail unless called by another cToken during the process of liquidation. + * Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter. + * @param liquidator The account receiving seized collateral + * @param borrower The account having collateral seized + * @param seizeTokens The number of cTokens to seize + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function seize(address liquidator, address borrower, uint seizeTokens) external nonReentrant returns (uint) { + /* Fail if seize not allowed */ + uint allowed = comptroller.seizeAllowed(address(this), msg.sender, liquidator, borrower, seizeTokens); + if (allowed != 0) { + return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, allowed); + } + + /* Fail if borrower = liquidator */ + if (borrower == liquidator) { + return fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER); + } + + MathError mathErr; + uint borrowerTokensNew; + uint liquidatorTokensNew; + + /* + * We calculate the new borrower and liquidator token balances, failing on underflow/overflow: + * borrowerTokensNew = accountTokens[borrower] - seizeTokens + * liquidatorTokensNew = accountTokens[liquidator] + seizeTokens + */ + (mathErr, borrowerTokensNew) = subUInt(accountTokens[borrower], seizeTokens); + if (mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, uint(mathErr)); + } + + (mathErr, liquidatorTokensNew) = addUInt(accountTokens[liquidator], seizeTokens); + if (mathErr != MathError.NO_ERROR) { + return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, uint(mathErr)); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + /* We write the previously calculated values into storage */ + accountTokens[borrower] = borrowerTokensNew; + accountTokens[liquidator] = liquidatorTokensNew; + + /* Emit a Transfer event */ + emit Transfer(borrower, liquidator, seizeTokens); + + /* We call the defense hook */ + comptroller.seizeVerify(address(this), msg.sender, liquidator, borrower, seizeTokens); + + return uint(Error.NO_ERROR); + } + + + /*** Admin Functions ***/ + + /** + * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. + * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. + * @param newPendingAdmin New pending admin. + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + * + * TODO: Should we add a second arg to verify, like a checksum of `newAdmin` address? + */ + function _setPendingAdmin(address payable newPendingAdmin) external returns (uint) { + // Check caller = admin + if (msg.sender != admin) { + return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK); + } + + // Save current value, if any, for inclusion in log + address oldPendingAdmin = pendingAdmin; + + // Store pendingAdmin with value newPendingAdmin + pendingAdmin = newPendingAdmin; + + // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) + emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin + * @dev Admin function for pending admin to accept role and update admin + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _acceptAdmin() external returns (uint) { + // Check caller is pendingAdmin and pendingAdmin ≠ address(0) + if (msg.sender != pendingAdmin || msg.sender == address(0)) { + return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK); + } + + // Save current values for inclusion in log + address oldAdmin = admin; + address oldPendingAdmin = pendingAdmin; + + // Store admin with value pendingAdmin + admin = pendingAdmin; + + // Clear the pending value + pendingAdmin = address(0); + + emit NewAdmin(oldAdmin, admin); + emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sets a new comptroller for the market + * @dev Admin function to set a new comptroller + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setComptroller(ComptrollerInterface newComptroller) public returns (uint) { + // Check caller is admin + if (msg.sender != admin) { + return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK); + } + + ComptrollerInterface oldComptroller = comptroller; + // Ensure invoke comptroller.isComptroller() returns true + require(newComptroller.isComptroller(), "marker method returned false"); + + // Set market's comptroller to newComptroller + comptroller = newComptroller; + + // Emit NewComptroller(oldComptroller, newComptroller) + emit NewComptroller(oldComptroller, newComptroller); + + return uint(Error.NO_ERROR); + } + + /** + * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh + * @dev Admin function to accrue interest and set a new reserve factor + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setReserveFactor(uint newReserveFactorMantissa) external nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reserve factor change failed. + return fail(Error(error), FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED); + } + // _setReserveFactorFresh emits reserve-factor-specific logs on errors, so we don't need to. + return _setReserveFactorFresh(newReserveFactorMantissa); + } + + /** + * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) + * @dev Admin function to set a new reserve factor + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) { + // Check caller is admin + if (msg.sender != admin) { + return fail(Error.UNAUTHORIZED, FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK); + } + + // Verify market's block number equals current block number + if (accrualBlockNumber != getBlockNumber()) { + // TODO: static_assert + no error code? + return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK); + } + + // Check newReserveFactor ≤ maxReserveFactor + if (newReserveFactorMantissa > reserveFactorMaxMantissa) { + return fail(Error.BAD_INPUT, FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK); + } + + uint oldReserveFactorMantissa = reserveFactorMantissa; + reserveFactorMantissa = newReserveFactorMantissa; + + emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Accrues interest and reduces reserves by transferring to admin + * @param reduceAmount Amount of reduction to reserves + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _reduceReserves(uint reduceAmount) external nonReentrant returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed. + return fail(Error(error), FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED); + } + // _reduceReservesFresh emits reserve-reduction-specific logs on errors, so we don't need to. + return _reduceReservesFresh(reduceAmount); + } + + /** + * @notice Reduces reserves by transferring to admin + * @dev Requires fresh interest accrual + * @param reduceAmount Amount of reduction to reserves + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _reduceReservesFresh(uint reduceAmount) internal returns (uint) { + Error err; + // totalReserves - reduceAmount + uint totalReservesNew; + + // Check caller is admin + if (msg.sender != admin) { + return fail(Error.UNAUTHORIZED, FailureInfo.REDUCE_RESERVES_ADMIN_CHECK); + } + + // We fail gracefully unless market's block number equals current block number + if (accrualBlockNumber != getBlockNumber()) { + // TODO: static_assert + no error code? + return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDUCE_RESERVES_FRESH_CHECK); + } + + // Fail gracefully if protocol has insufficient underlying cash + if (getCashPrior() < reduceAmount) { + return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE); + } + + // Check reduceAmount ≤ reserves[n] (totalReserves) + // TODO: I'm following the spec literally here but I think we should we just use SafeMath instead and fail on an error (which would be underflow) + if (reduceAmount > totalReserves) { + return fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); + } + + ///////////////////////// + // EFFECTS & INTERACTIONS + // (No safe failures beyond this point) + + totalReservesNew = totalReserves - reduceAmount; + // We checked reduceAmount <= totalReserves above, so this should never revert. + require(totalReservesNew <= totalReserves, "reduce reserves unexpected underflow"); + + // Store reserves[n+1] = reserves[n] - reduceAmount + totalReserves = totalReservesNew; + + // invoke doTransferOut(reduceAmount, admin) + err = doTransferOut(admin, reduceAmount); + // we revert on the failure of this command + require(err == Error.NO_ERROR, "reduce reserves transfer out failed"); + + emit ReservesReduced(admin, reduceAmount, totalReservesNew); + + return uint(Error.NO_ERROR); + } + + /** + * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh + * @dev Admin function to accrue interest and update the interest rate model + * @param newInterestRateModel the new interest rate model to use + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint) { + uint error = accrueInterest(); + if (error != uint(Error.NO_ERROR)) { + // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted change of interest rate model failed + return fail(Error(error), FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED); + } + // _setInterestRateModelFresh emits interest-rate-model-update-specific logs on errors, so we don't need to. + return _setInterestRateModelFresh(newInterestRateModel); + } + + /** + * @notice updates the interest rate model (*requires fresh interest accrual) + * @dev Admin function to update the interest rate model + * @param newInterestRateModel the new interest rate model to use + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal returns (uint) { + + // Used to store old model for use in the event that is emitted on success + InterestRateModel oldInterestRateModel; + + // Check caller is admin + if (msg.sender != admin) { + return fail(Error.UNAUTHORIZED, FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK); + } + + // We fail gracefully unless market's block number equals current block number + if (accrualBlockNumber != getBlockNumber()) { + // TODO: static_assert + no error code? + return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK); + } + + // Track the market's current interest rate model + oldInterestRateModel = interestRateModel; + + // Ensure invoke newInterestRateModel.isInterestRateModel() returns true + require(newInterestRateModel.isInterestRateModel(), "marker method returned false"); + + // Set the interest rate model to newInterestRateModel + interestRateModel = newInterestRateModel; + + // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel) + emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel); + + return uint(Error.NO_ERROR); + } + + /*** Safe Token ***/ + + /** + * @notice Gets balance of this contract in terms of the underlying + * @dev This excludes the value of the current message, if any + * @return The quantity of underlying owned by this contract + */ + function getCashPrior() internal view returns (uint); + + /** + * @dev Checks whether or not there is sufficient allowance for this contract to move amount from `from` and + * whether or not `from` has a balance of at least `amount`. Does NOT do a transfer. + */ + function checkTransferIn(address from, uint amount) internal view returns (Error); + + /** + * @dev Performs a transfer in, ideally returning an explanatory error code upon failure rather than reverting. + * If caller has not called `checkTransferIn`, this may revert due to insufficient balance or insufficient allowance. + * If caller has called `checkTransferIn` successfully, this should not revert in normal conditions. + */ + function doTransferIn(address from, uint amount) internal returns (Error); + + /** + * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting. + * If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract. + * If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions. + */ + function doTransferOut(address payable to, uint amount) internal returns (Error); +} diff --git a/contracts/CarefulMath.sol b/contracts/CarefulMath.sol new file mode 100644 index 000000000..1670342c1 --- /dev/null +++ b/contracts/CarefulMath.sol @@ -0,0 +1,85 @@ +pragma solidity ^0.5.8; + +/** + * @title Careful Math + * @author Compound + * @notice Derived from OpenZeppelin's SafeMath library + * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol + */ +contract CarefulMath { + + /** + * @dev Possible error codes that we can return + */ + enum MathError { + NO_ERROR, + DIVISION_BY_ZERO, + INTEGER_OVERFLOW, + INTEGER_UNDERFLOW + } + + /** + * @dev Multiplies two numbers, returns an error on overflow. + */ + function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { + if (a == 0) { + return (MathError.NO_ERROR, 0); + } + + uint c = a * b; + + if (c / a != b) { + return (MathError.INTEGER_OVERFLOW, 0); + } else { + return (MathError.NO_ERROR, c); + } + } + + /** + * @dev Integer division of two numbers, truncating the quotient. + */ + function divUInt(uint a, uint b) internal pure returns (MathError, uint) { + if (b == 0) { + return (MathError.DIVISION_BY_ZERO, 0); + } + + return (MathError.NO_ERROR, a / b); + } + + /** + * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). + */ + function subUInt(uint a, uint b) internal pure returns (MathError, uint) { + if (b <= a) { + return (MathError.NO_ERROR, a - b); + } else { + return (MathError.INTEGER_UNDERFLOW, 0); + } + } + + /** + * @dev Adds two numbers, returns an error on overflow. + */ + function addUInt(uint a, uint b) internal pure returns (MathError, uint) { + uint c = a + b; + + if (c >= a) { + return (MathError.NO_ERROR, c); + } else { + return (MathError.INTEGER_OVERFLOW, 0); + } + } + + /** + * @dev add a and b and then subtract c + */ + function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { + (MathError err0, uint sum) = addUInt(a, b); + + if (err0 != MathError.NO_ERROR) { + return (err0, 0); + } + + return subUInt(sum, c); + } +} \ No newline at end of file diff --git a/contracts/Comptroller.sol b/contracts/Comptroller.sol new file mode 100644 index 000000000..2991b77cf --- /dev/null +++ b/contracts/Comptroller.sol @@ -0,0 +1,996 @@ +pragma solidity ^0.5.8; + +import "./CToken.sol"; +import "./ErrorReporter.sol"; +import "./Exponential.sol"; +import "./PriceOracle.sol"; +import "./ComptrollerInterface.sol"; +import "./ComptrollerStorage.sol"; +import "./Unitroller.sol"; + +/** + * @title Compound's Comptroller Contract + * @author Compound + */ +contract Comptroller is ComptrollerV1Storage, ComptrollerInterface, ComptrollerErrorReporter, Exponential { + struct Market { + /** + * @notice Whether or not this market is listed + */ + bool isListed; + + /** + * @notice Multiplier representing the most one can borrow against their collateral in this market. + * For instance, 0.9 to allow borrowing 90% of collateral value. + * Must be between 0 and 1, and stored as a mantissa. + */ + uint collateralFactorMantissa; + + /** + * @notice Per-market mapping of "accounts in this asset" + */ + mapping(address => bool) accountMembership; + } + + /** + * @notice Official mapping of cTokens -> Market metadata + * @dev Used e.g. to determine if a market is supported + */ + mapping(address => Market) public markets; + + /** + * @notice Emitted when an admin supports a market + */ + event MarketListed(CToken cToken); + + /** + * @notice Emitted when an account enters a market + */ + event MarketEntered(CToken cToken, address account); + + /** + * @notice Emitted when an account exits a market + */ + event MarketExited(CToken cToken, address account); + + /** + * @notice Emitted when close factor is changed by admin + */ + event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa); + + /** + * @notice Emitted when a collateral factor is changed by admin + */ + event NewCollateralFactor(CToken cToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa); + + /** + * @notice Emitted when liquidation incentive is changed by admin + */ + event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa); + + /** + * @notice Emitted when maxAssets is changed by admin + */ + event NewMaxAssets(uint oldMaxAssets, uint newMaxAssets); + + /** + * @notice Emitted when price oracle is changed + */ + event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle); + + /** + * @notice Indicator that this is a Comptroller contract (for inspection) + */ + bool public constant isComptroller = true; + + // closeFactorMantissa must be strictly greater than this value + uint constant closeFactorMinMantissa = 5e16; // 0.05 + + // closeFactorMantissa must not exceed this value + uint constant closeFactorMaxMantissa = 9e17; // 0.9 + + // No collateralFactorMantissa may exceed this value + uint constant collateralFactorMaxMantissa = 9e17; // 0.9 + + // liquidationIncentiveMantissa must be no less than this value + uint constant liquidationIncentiveMinMantissa = mantissaOne; + + // liquidationIncentiveMantissa must be no greater than this value + uint constant liquidationIncentiveMaxMantissa = 15e17; // 1.5 + + constructor() public { + admin = msg.sender; + } + + /*** Assets You Are In ***/ + + /** + * @notice Returns the assets an account has entered + * @param account The address of the account to pull assets for + * @return A dynamic list with the assets the account has entered + */ + function getAssetsIn(address account) external view returns (CToken[] memory) { + CToken[] memory assetsIn = accountAssets[account]; + + return assetsIn; + } + + /** + * @notice Returns whether the given account is entered in the given asset + * @param account The address of the account to check + * @param cToken The cToken to check + * @return True if the account is in the asset, otherwise false. + */ + function checkMembership(address account, CToken cToken) external view returns (bool) { + return markets[address(cToken)].accountMembership[account]; + } + + /** + * @notice Add assets to be included in account liquidity calculation + * @param cTokens The list of addresses of the cToken markets to be enabled + * @return Success indicator for whether each corresponding market was entered + */ + function enterMarkets(address[] memory cTokens) public returns (uint[] memory) { + uint len = cTokens.length; + + uint[] memory results = new uint[](len); + for (uint i = 0; i < len; i++) { + CToken cToken = CToken(cTokens[i]); + Market storage marketToJoin = markets[address(cToken)]; + + if (!marketToJoin.isListed) { + // if market is not listed, cannot join move along + results[i] = uint(Error.MARKET_NOT_LISTED); + continue; + } + + if (marketToJoin.accountMembership[msg.sender] == true) { + // if already joined, move along + results[i] = uint(Error.NO_ERROR); + continue; + } + + if (accountAssets[msg.sender].length >= maxAssets) { + // if no space, cannot join, move along + results[i] = uint(Error.TOO_MANY_ASSETS); + continue; + } + + // survived the gauntlet, add to list + // NOTE: we store these somewhat redundantly as a significant optimization + // this avoids having to iterate through the list for the most common use cases + // that is, only when we need to perform liquidity checks + // and not whenever we want to check if an account is in a particular market + marketToJoin.accountMembership[msg.sender] = true; + accountAssets[msg.sender].push(cToken); + + emit MarketEntered(cToken, msg.sender); + + results[i] = uint(Error.NO_ERROR); + } + + return results; + } + + /** + * @notice Removes asset from sender's account liquidity calculation + * @dev Sender must not have an outstanding borrow balance in the asset, + * or be providing neccessary collateral for an outstanding borrow. + * @param cTokenAddress The address of the asset to be removed + * @return Whether or not the account successfully exited the market + */ + function exitMarket(address cTokenAddress) external returns (uint) { + CToken cToken = CToken(cTokenAddress); + /* Get sender tokensHeld and amountOwed underlying from the cToken */ + (uint oErr, uint tokensHeld, uint amountOwed, ) = cToken.getAccountSnapshot(msg.sender); + require(oErr == 0, "exitMarket: getAccountSnapshot failed"); // semi-opaque error code + + /* Fail if the sender has a borrow balance */ + if (amountOwed != 0) { + return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED); + } + + /* Fail if the sender is not permitted to redeem all of their tokens */ + uint allowed = redeemAllowedInternal(cTokenAddress, msg.sender, tokensHeld); + if (allowed != 0) { + return failOpaque(Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed); + } + + Market storage marketToExit = markets[address(cToken)]; + + /* Return true if the sender is not already ‘in’ the market */ + if (!marketToExit.accountMembership[msg.sender]) { + return uint(Error.NO_ERROR); + } + + /* Set cToken account membership to false */ + delete marketToExit.accountMembership[msg.sender]; + + /* Delete cToken from the account’s list of assets */ + // load into memory for faster iteration + CToken[] memory userAssetList = accountAssets[msg.sender]; + uint len = userAssetList.length; + uint assetIndex = len; + for (uint i = 0; i < len; i++) { + if (userAssetList[i] == cToken) { + assetIndex = i; + break; + } + } + + // We *must* have found the asset in the list or our redundant data structure is broken + assert(assetIndex < len); + + // copy last item in list to location of item to be removed, reduce length by 1 + CToken[] storage storedList = accountAssets[msg.sender]; + storedList[assetIndex] = storedList[storedList.length - 1]; + storedList.length--; + + emit MarketExited(cToken, msg.sender); + + return uint(Error.NO_ERROR); + } + + /*** Policy Hooks ***/ + + /** + * @notice Checks if the account should be allowed to mint tokens in the given market + * @param cToken The market to verify the mint against + * @param minter The account which would get the minted tokens + * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens + * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) + */ + function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint) { + minter; // currently unused + mintAmount; // currently unused + + if (!markets[cToken].isListed) { + return uint(Error.MARKET_NOT_LISTED); + } + + // *may include Policy Hook-type checks + + return uint(Error.NO_ERROR); + } + + /** + * @notice Validates mint and reverts on rejection. May emit logs. + * @param cToken Asset being minted + * @param minter The address minting the tokens + * @param mintAmount The amount of the underlying asset being minted + * @param mintTokens The number of tokens being minted + */ + function mintVerify(address cToken, address minter, uint mintAmount, uint mintTokens) external { + cToken; // currently unused + minter; // currently unused + mintAmount; // currently unused + mintTokens; // currently unused + + if (false) { + maxAssets = maxAssets; // not pure + } + } + + /** + * @notice Checks if the account should be allowed to redeem tokens in the given market + * @param cToken The market to verify the redeem against + * @param redeemer The account which would redeem the tokens + * @param redeemTokens The number of cTokens to exchange for the underlying asset in the market + * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) + */ + function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint) { + return redeemAllowedInternal(cToken, redeemer, redeemTokens); + } + + function redeemAllowedInternal(address cToken, address redeemer, uint redeemTokens) internal view returns (uint) { + if (!markets[cToken].isListed) { + return uint(Error.MARKET_NOT_LISTED); + } + + // *may include Policy Hook-type checks + + /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */ + if (!markets[cToken].accountMembership[redeemer]) { + return uint(Error.NO_ERROR); + } + + /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */ + (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, CToken(cToken), redeemTokens, 0); + if (err != Error.NO_ERROR) { + return uint(err); + } + if (shortfall > 0) { + return uint(Error.INSUFFICIENT_LIQUIDITY); + } + + return uint(Error.NO_ERROR); + } + + /** + * @notice Validates redeem and reverts on rejection. May emit logs. + * @param cToken Asset being redeemed + * @param redeemer The address redeeming the tokens + * @param redeemAmount The amount of the underlying asset being redeemed + * @param redeemTokens The number of tokens being redeemed + */ + function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external { + cToken; // currently unused + redeemer; // currently unused + redeemAmount; // currently unused + redeemTokens; // currently unused + + // Require tokens is zero or amount is also zero + if (redeemTokens == 0 && redeemAmount > 0) { + revert("redeemTokens zero"); + } + } + + /** + * @notice Checks if the account should be allowed to borrow the underlying asset of the given market + * @param cToken The market to verify the borrow against + * @param borrower The account which would borrow the asset + * @param borrowAmount The amount of underlying the account would borrow + * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) + */ + function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint) { + if (!markets[cToken].isListed) { + return uint(Error.MARKET_NOT_LISTED); + } + + // *may include Policy Hook-type checks + + if (!markets[cToken].accountMembership[borrower]) { + return uint(Error.MARKET_NOT_ENTERED); + } + + if (oracle.getUnderlyingPrice(CToken(cToken)) == 0) { + return uint(Error.PRICE_ERROR); + } + + (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(borrower, CToken(cToken), 0, borrowAmount); + if (err != Error.NO_ERROR) { + return uint(err); + } + if (shortfall > 0) { + return uint(Error.INSUFFICIENT_LIQUIDITY); + } + + return uint(Error.NO_ERROR); + } + + /** + * @notice Validates borrow and reverts on rejection. May emit logs. + * @param cToken Asset whose underlying is being borrowed + * @param borrower The address borrowing the underlying + * @param borrowAmount The amount of the underlying asset requested to borrow + */ + function borrowVerify(address cToken, address borrower, uint borrowAmount) external { + cToken; // currently unused + borrower; // currently unused + borrowAmount; // currently unused + + if (false) { + maxAssets = maxAssets; // not pure + } + } + + /** + * @notice Checks if the account should be allowed to repay a borrow in the given market + * @param cToken The market to verify the repay against + * @param payer The account which would repay the asset + * @param borrower The account which would borrowed the asset + * @param repayAmount The amount of the underlying asset the account would repay + * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) + */ + function repayBorrowAllowed( + address cToken, + address payer, + address borrower, + uint repayAmount) external returns (uint) { + payer; // currently unused + borrower; // currently unused + repayAmount; // currently unused + + if (!markets[cToken].isListed) { + return uint(Error.MARKET_NOT_LISTED); + } + + // *may include Policy Hook-type checks + + return uint(Error.NO_ERROR); + } + + /** + * @notice Validates repayBorrow and reverts on rejection. May emit logs. + * @param cToken Asset being repaid + * @param payer The address repaying the borrow + * @param borrower The address of the borrower + * @param repayAmount The amount of underlying being repaid + */ + function repayBorrowVerify( + address cToken, + address payer, + address borrower, + uint repayAmount, + uint borrowerIndex) external { + cToken; // currently unused + payer; // currently unused + borrower; // currently unused + repayAmount; // currently unused + borrowerIndex; // currently unused + + if (false) { + maxAssets = maxAssets; // not pure + } + } + + /** + * @notice Checks if the liquidation should be allowed to occur + * @param cTokenBorrowed Asset which was borrowed by the borrower + * @param cTokenCollateral Asset which was used as collateral and will be seized + * @param liquidator The address repaying the borrow and seizing the collateral + * @param borrower The address of the borrower + * @param repayAmount The amount of underlying being repaid + */ + function liquidateBorrowAllowed( + address cTokenBorrowed, + address cTokenCollateral, + address liquidator, + address borrower, + uint repayAmount) external returns (uint) { + liquidator; // currently unused + borrower; // currently unused + repayAmount; // currently unused + + if (!markets[cTokenBorrowed].isListed || !markets[cTokenCollateral].isListed) { + return uint(Error.MARKET_NOT_LISTED); + } + + // *may include Policy Hook-type checks + + /* The borrower must have shortfall in order to be liquidatable */ + (Error err, , uint shortfall) = getAccountLiquidityInternal(borrower); + if (err != Error.NO_ERROR) { + return uint(err); + } + if (shortfall == 0) { + return uint(Error.INSUFFICIENT_SHORTFALL); + } + + /* The liquidator may not repay more than what is allowed by the closeFactor */ + uint borrowBalance = CToken(cTokenBorrowed).borrowBalanceStored(borrower); + (MathError mathErr, uint maxClose) = mulScalarTruncate(Exp({mantissa: closeFactorMantissa}), borrowBalance); + if (mathErr != MathError.NO_ERROR) { + return uint(Error.MATH_ERROR); + } + if (repayAmount > maxClose) { + return uint(Error.TOO_MUCH_REPAY); + } + + return uint(Error.NO_ERROR); + } + + /** + * @notice Validates liquidateBorrow and reverts on rejection. May emit logs. + * @param cTokenBorrowed Asset which was borrowed by the borrower + * @param cTokenCollateral Asset which was used as collateral and will be seized + * @param liquidator The address repaying the borrow and seizing the collateral + * @param borrower The address of the borrower + * @param repayAmount The amount of underlying being repaid + */ + function liquidateBorrowVerify( + address cTokenBorrowed, + address cTokenCollateral, + address liquidator, + address borrower, + uint repayAmount, + uint seizeTokens) external { + cTokenBorrowed; // currently unused + cTokenCollateral; // currently unused + liquidator; // currently unused + borrower; // currently unused + repayAmount; // currently unused + seizeTokens; // currently unused + + if (false) { + maxAssets = maxAssets; // not pure + } + } + + /** + * @notice Checks if the seizing of assets should be allowed to occur + * @param cTokenCollateral Asset which was used as collateral and will be seized + * @param cTokenBorrowed Asset which was borrowed by the borrower + * @param liquidator The address repaying the borrow and seizing the collateral + * @param borrower The address of the borrower + * @param seizeTokens The number of collateral tokens to seize + */ + function seizeAllowed( + address cTokenCollateral, + address cTokenBorrowed, + address liquidator, + address borrower, + uint seizeTokens) external returns (uint) { + liquidator; // currently unused + borrower; // currently unused + seizeTokens; // currently unused + + if (!markets[cTokenCollateral].isListed || !markets[cTokenBorrowed].isListed) { + return uint(Error.MARKET_NOT_LISTED); + } + + if (CToken(cTokenCollateral).comptroller() != CToken(cTokenBorrowed).comptroller()) { + return uint(Error.COMPTROLLER_MISMATCH); + } + + // *may include Policy Hook-type checks + + return uint(Error.NO_ERROR); + } + + /** + * @notice Validates seize and reverts on rejection. May emit logs. + * @param cTokenCollateral Asset which was used as collateral and will be seized + * @param cTokenBorrowed Asset which was borrowed by the borrower + * @param liquidator The address repaying the borrow and seizing the collateral + * @param borrower The address of the borrower + * @param seizeTokens The number of collateral tokens to seize + */ + function seizeVerify( + address cTokenCollateral, + address cTokenBorrowed, + address liquidator, + address borrower, + uint seizeTokens) external { + cTokenCollateral; // currently unused + cTokenBorrowed; // currently unused + liquidator; // currently unused + borrower; // currently unused + seizeTokens; // currently unused + + if (false) { + maxAssets = maxAssets; // not pure + } + } + + /** + * @notice Checks if the account should be allowed to transfer tokens in the given market + * @param cToken The market to verify the transfer against + * @param src The account which sources the tokens + * @param dst The account which receives the tokens + * @param transferTokens The number of cTokens to transfer + * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol) + */ + function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint) { + cToken; // currently unused + src; // currently unused + dst; // currently unused + transferTokens; // currently unused + + // *may include Policy Hook-type checks + + // Currently the only consideration is whether or not + // the src is allowed to redeem this many tokens + return redeemAllowedInternal(cToken, src, transferTokens); + } + + /** + * @notice Validates transfer and reverts on rejection. May emit logs. + * @param cToken Asset being transferred + * @param src The account which sources the tokens + * @param dst The account which receives the tokens + * @param transferTokens The number of cTokens to transfer + */ + function transferVerify(address cToken, address src, address dst, uint transferTokens) external { + cToken; // currently unused + src; // currently unused + dst; // currently unused + transferTokens; // currently unused + + if (false) { + maxAssets = maxAssets; // not pure + } + } + + /*** Liquidity/Liquidation Calculations ***/ + + /** + * @dev Local vars for avoiding stack-depth limits in calculating account liquidity. + * Note that `cTokenBalance` is the number of cTokens the account owns in the market, + * whereas `borrowBalance` is the amount of underlying that the account has borrowed. + */ + struct AccountLiquidityLocalVars { + uint sumCollateral; + uint sumBorrowPlusEffects; + uint cTokenBalance; + uint borrowBalance; + uint exchangeRateMantissa; + uint oraclePriceMantissa; + Exp collateralFactor; + Exp exchangeRate; + Exp oraclePrice; + Exp tokensToEther; + } + + /** + * @notice Determine the current account liquidity wrt collateral requirements + * @return (possible error code (semi-opaque), + account liquidity in excess of collateral requirements, + * account shortfall below collateral requirements) + */ + function getAccountLiquidity(address account) public view returns (uint, uint, uint) { + (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0); + + return (uint(err), liquidity, shortfall); + } + + /** + * @notice Determine the current account liquidity wrt collateral requirements + * @return (possible error code, + account liquidity in excess of collateral requirements, + * account shortfall below collateral requirements) + */ + function getAccountLiquidityInternal(address account) internal view returns (Error, uint, uint) { + return getHypotheticalAccountLiquidityInternal(account, CToken(0), 0, 0); + } + + /** + * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed + * @param cTokenModify The market to hypothetically redeem/borrow in + * @param account The account to determine liquidity for + * @param redeemTokens The number of tokens to hypothetically redeem + * @param borrowAmount The amount of underlying to hypothetically borrow + * @dev Note that we calculate the exchangeRateStored for each collateral cToken using stored data, + * without calculating accumulated interest. + * @return (possible error code, + hypothetical account liquidity in excess of collateral requirements, + * hypothetical account shortfall below collateral requirements) + */ + function getHypotheticalAccountLiquidityInternal( + address account, + CToken cTokenModify, + uint redeemTokens, + uint borrowAmount) internal view returns (Error, uint, uint) { + + AccountLiquidityLocalVars memory vars; // Holds all our calculation results + uint oErr; + MathError mErr; + + // For each asset the account is in + CToken[] memory assets = accountAssets[account]; + for (uint i = 0; i < assets.length; i++) { + CToken asset = assets[i]; + + // Read the balances and exchange rate from the cToken + (oErr, vars.cTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = asset.getAccountSnapshot(account); + if (oErr != 0) { // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades + return (Error.SNAPSHOT_ERROR, 0, 0); + } + vars.collateralFactor = Exp({mantissa: markets[address(asset)].collateralFactorMantissa}); + vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa}); + + // Get the normalized price of the asset + vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset); + if (vars.oraclePriceMantissa == 0) { + return (Error.PRICE_ERROR, 0, 0); + } + vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa}); + + // Pre-compute a conversion factor from tokens -> ether (normalized price value) + (mErr, vars.tokensToEther) = mulExp3(vars.collateralFactor, vars.exchangeRate, vars.oraclePrice); + if (mErr != MathError.NO_ERROR) { + return (Error.MATH_ERROR, 0, 0); + } + + // sumCollateral += tokensToEther * cTokenBalance + (mErr, vars.sumCollateral) = mulScalarTruncateAddUInt(vars.tokensToEther, vars.cTokenBalance, vars.sumCollateral); + if (mErr != MathError.NO_ERROR) { + return (Error.MATH_ERROR, 0, 0); + } + + // sumBorrowPlusEffects += oraclePrice * borrowBalance + (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects); + if (mErr != MathError.NO_ERROR) { + return (Error.MATH_ERROR, 0, 0); + } + + // Calculate effects of interacting with cTokenModify + if (asset == cTokenModify) { + // redeem effect + // sumBorrowPlusEffects += tokensToEther * redeemTokens + (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.tokensToEther, redeemTokens, vars.sumBorrowPlusEffects); + if (mErr != MathError.NO_ERROR) { + return (Error.MATH_ERROR, 0, 0); + } + + // borrow effect + // sumBorrowPlusEffects += oraclePrice * borrowAmount + (mErr, vars.sumBorrowPlusEffects) = mulScalarTruncateAddUInt(vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects); + if (mErr != MathError.NO_ERROR) { + return (Error.MATH_ERROR, 0, 0); + } + } + } + + // These are safe, as the underflow condition is checked first + if (vars.sumCollateral > vars.sumBorrowPlusEffects) { + return (Error.NO_ERROR, vars.sumCollateral - vars.sumBorrowPlusEffects, 0); + } else { + return (Error.NO_ERROR, 0, vars.sumBorrowPlusEffects - vars.sumCollateral); + } + } + + /** + * @notice Calculate number of tokens of collateral asset to seize given an underlying amount + * @dev Used in liquidation (called in cToken.liquidateBorrowFresh) + * @param cTokenBorrowed The address of the borrowed cToken + * @param cTokenCollateral The address of the collateral cToken + * @param repayAmount The amount of cTokenBorrowed underlying to convert into cTokenCollateral tokens + * @return (errorCode, number of cTokenCollateral tokens to be seized in a liquidation) + */ + function liquidateCalculateSeizeTokens(address cTokenBorrowed, address cTokenCollateral, uint repayAmount) external view returns (uint, uint) { + /* Read oracle prices for borrowed and collateral markets */ + uint priceBorrowedMantissa = oracle.getUnderlyingPrice(CToken(cTokenBorrowed)); + uint priceCollateralMantissa = oracle.getUnderlyingPrice(CToken(cTokenCollateral)); + if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) { + return (uint(Error.PRICE_ERROR), 0); + } + + /* + * Get the exchange rate and calculate the number of collateral tokens to seize: + * seizeAmount = repayAmount * liquidationIncentive * priceBorrowed / priceCollateral + * seizeTokens = seizeAmount / exchangeRate + * = repayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate) + */ + uint exchangeRateMantissa = CToken(cTokenCollateral).exchangeRateStored(); // Note: reverts on error + uint seizeTokens; + Exp memory numerator; + Exp memory denominator; + Exp memory ratio; + MathError mathErr; + + (mathErr, numerator) = mulExp(liquidationIncentiveMantissa, priceBorrowedMantissa); + if (mathErr != MathError.NO_ERROR) { + return (uint(Error.MATH_ERROR), 0); + } + + (mathErr, denominator) = mulExp(priceCollateralMantissa, exchangeRateMantissa); + if (mathErr != MathError.NO_ERROR) { + return (uint(Error.MATH_ERROR), 0); + } + + (mathErr, ratio) = divExp(numerator, denominator); + if (mathErr != MathError.NO_ERROR) { + return (uint(Error.MATH_ERROR), 0); + } + + (mathErr, seizeTokens) = mulScalarTruncate(ratio, repayAmount); + if (mathErr != MathError.NO_ERROR) { + return (uint(Error.MATH_ERROR), 0); + } + + return (uint(Error.NO_ERROR), seizeTokens); + } + + /*** Admin Functions ***/ + + /** + * @notice Sets a new price oracle for the comptroller + * @dev Admin function to set a new price oracle + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setPriceOracle(PriceOracle newOracle) public returns (uint) { + // Check caller is admin OR currently initialzing as new unitroller implementation + if (!adminOrInitializing()) { + return fail(Error.UNAUTHORIZED, FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK); + } + + // Track the old oracle for the comptroller + PriceOracle oldOracle = oracle; + + // Ensure invoke newOracle.isPriceOracle() returns true + // require(newOracle.isPriceOracle(), "oracle method isPriceOracle returned false"); + + // Set comptroller's oracle to newOracle + oracle = newOracle; + + // Emit NewPriceOracle(oldOracle, newOracle) + emit NewPriceOracle(oldOracle, newOracle); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sets the closeFactor used when liquidating borrows + * @dev Admin function to set closeFactor + * @param newCloseFactorMantissa New close factor, scaled by 1e18 + * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) + */ + function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint256) { + // Check caller is admin OR currently initialzing as new unitroller implementation + if (!adminOrInitializing()) { + return fail(Error.UNAUTHORIZED, FailureInfo.SET_CLOSE_FACTOR_OWNER_CHECK); + } + + Exp memory newCloseFactorExp = Exp({mantissa: newCloseFactorMantissa}); + Exp memory lowLimit = Exp({mantissa: closeFactorMinMantissa}); + if (lessThanOrEqualExp(newCloseFactorExp, lowLimit)) { + return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION); + } + + Exp memory highLimit = Exp({mantissa: closeFactorMaxMantissa}); + if (lessThanExp(highLimit, newCloseFactorExp)) { + return fail(Error.INVALID_CLOSE_FACTOR, FailureInfo.SET_CLOSE_FACTOR_VALIDATION); + } + + uint oldCloseFactorMantissa = closeFactorMantissa; + closeFactorMantissa = newCloseFactorMantissa; + emit NewCloseFactor(oldCloseFactorMantissa, closeFactorMantissa); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sets the collateralFactor for a market + * @dev Admin function to set per-market collateralFactor + * @param cToken The market to set the factor on + * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18 + * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) + */ + function _setCollateralFactor(CToken cToken, uint newCollateralFactorMantissa) external returns (uint256) { + // Check caller is admin + if (msg.sender != admin) { + return fail(Error.UNAUTHORIZED, FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK); + } + + // Verify market is listed + Market storage market = markets[address(cToken)]; + if (!market.isListed) { + return fail(Error.MARKET_NOT_LISTED, FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS); + } + + Exp memory newCollateralFactorExp = Exp({mantissa: newCollateralFactorMantissa}); + + // Check collateral factor <= 0.9 + Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa}); + if (lessThanExp(highLimit, newCollateralFactorExp)) { + return fail(Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION); + } + + // If collateral factor != 0, fail if price == 0 + if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(cToken) == 0) { + return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE); + } + + // Set market's collateral factor to new collateral factor, remember old value + uint oldCollateralFactorMantissa = market.collateralFactorMantissa; + market.collateralFactorMantissa = newCollateralFactorMantissa; + + // Emit event with asset, old collateral factor, and new collateral factor + emit NewCollateralFactor(cToken, oldCollateralFactorMantissa, newCollateralFactorMantissa); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sets maxAssets which controls how many markets can be entered + * @dev Admin function to set maxAssets + * @param newMaxAssets New max assets + * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) + */ + function _setMaxAssets(uint newMaxAssets) external returns (uint) { + // Check caller is admin OR currently initialzing as new unitroller implementation + if (!adminOrInitializing()) { + return fail(Error.UNAUTHORIZED, FailureInfo.SET_MAX_ASSETS_OWNER_CHECK); + } + + uint oldMaxAssets = maxAssets; + maxAssets = newMaxAssets; + emit NewMaxAssets(oldMaxAssets, newMaxAssets); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sets liquidationIncentive + * @dev Admin function to set liquidationIncentive + * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18 + * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) + */ + function _setLiquidationIncentive(uint newLiquidationIncentiveMantissa) external returns (uint) { + // Check caller is admin OR currently initialzing as new unitroller implementation + if (!adminOrInitializing()) { + return fail(Error.UNAUTHORIZED, FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK); + } + + // Check de-scaled 1 <= newLiquidationDiscount <= 1.5 + Exp memory newLiquidationIncentive = Exp({mantissa: newLiquidationIncentiveMantissa}); + Exp memory minLiquidationIncentive = Exp({mantissa: liquidationIncentiveMinMantissa}); + if (lessThanExp(newLiquidationIncentive, minLiquidationIncentive)) { + return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION); + } + + Exp memory maxLiquidationIncentive = Exp({mantissa: liquidationIncentiveMaxMantissa}); + if (lessThanExp(maxLiquidationIncentive, newLiquidationIncentive)) { + return fail(Error.INVALID_LIQUIDATION_INCENTIVE, FailureInfo.SET_LIQUIDATION_INCENTIVE_VALIDATION); + } + + // Save current value for use in log + uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa; + + // Set liquidation incentive to new incentive + liquidationIncentiveMantissa = newLiquidationIncentiveMantissa; + + // Emit event with old incentive, new incentive + emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Add the market to the markets mapping and set it as listed + * @dev Admin function to set isListed and add support for the market + * @param cToken The address of the market (token) to list + * @return uint 0=success, otherwise a failure. (See enum Error for details) + */ + function _supportMarket(CToken cToken) external returns (uint) { + if (msg.sender != admin) { + return fail(Error.UNAUTHORIZED, FailureInfo.SUPPORT_MARKET_OWNER_CHECK); + } + + if (markets[address(cToken)].isListed) { + return fail(Error.MARKET_ALREADY_LISTED, FailureInfo.SUPPORT_MARKET_EXISTS); + } + + cToken.isCToken(); // Sanity check to make sure its really a CToken + + markets[address(cToken)] = Market({isListed: true, collateralFactorMantissa: 0}); + emit MarketListed(cToken); + + return uint(Error.NO_ERROR); + } + + function _become(Unitroller unitroller, PriceOracle _oracle, uint _closeFactorMantissa, uint _maxAssets, bool reinitializing) public { + require(msg.sender == unitroller.admin(), "only unitroller admin can change brains"); + uint changeStatus = unitroller._acceptImplementation(); + + require(changeStatus == 0, "change not authorized"); + + if (!reinitializing) { + Comptroller freshBrainedComptroller = Comptroller(address(unitroller)); + + // Ensure invoke _setPriceOracle() = 0 + uint err = freshBrainedComptroller._setPriceOracle(_oracle); + require (err == uint(Error.NO_ERROR), "set price oracle error"); + + // Ensure invoke _setCloseFactor() = 0 + err = freshBrainedComptroller._setCloseFactor(_closeFactorMantissa); + require (err == uint(Error.NO_ERROR), "set close factor error"); + + // Ensure invoke _setMaxAssets() = 0 + err = freshBrainedComptroller._setMaxAssets(_maxAssets); + require (err == uint(Error.NO_ERROR), "set max asssets error"); + + // Ensure invoke _setLiquidationIncentive(liquidationIncentiveMinMantissa) = 0 + err = freshBrainedComptroller._setLiquidationIncentive(liquidationIncentiveMinMantissa); + require (err == uint(Error.NO_ERROR), "set liquidation incentive error"); + } + } + + /** + * @dev Check that caller is admin or this contract is initializing itself as + * the new implementation. + * There should be no way to satisfy msg.sender == comptrollerImplementaiton + * without tx.origin also being admin, but both are included for extra safety + */ + function adminOrInitializing() internal view returns (bool) { + bool initializing = ( + msg.sender == comptrollerImplementation + && + //solium-disable-next-line security/no-tx-origin + tx.origin == admin + ); + bool isAdmin = msg.sender == admin; + return isAdmin || initializing; + } +} diff --git a/contracts/ComptrollerInterface.sol b/contracts/ComptrollerInterface.sol new file mode 100644 index 000000000..255fb922b --- /dev/null +++ b/contracts/ComptrollerInterface.sol @@ -0,0 +1,75 @@ +pragma solidity ^0.5.8; + +interface ComptrollerInterface { + /** + * @notice Marker function used for light validation when updating the comptroller of a market + * @dev Implementations should simply return true. + * @return true + */ + function isComptroller() external view returns (bool); + + /*** Assets You Are In ***/ + + function enterMarkets(address[] calldata cTokens) external returns (uint[] memory); + function exitMarket(address cToken) external returns (uint); + + /*** Policy Hooks ***/ + + function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint); + function mintVerify(address cToken, address minter, uint mintAmount, uint mintTokens) external; + + function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint); + function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external; + + function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint); + function borrowVerify(address cToken, address borrower, uint borrowAmount) external; + + function repayBorrowAllowed( + address cToken, + address payer, + address borrower, + uint repayAmount) external returns (uint); + function repayBorrowVerify( + address cToken, + address payer, + address borrower, + uint repayAmount, + uint borrowerIndex) external; + + function liquidateBorrowAllowed( + address cTokenBorrowed, + address cTokenCollateral, + address liquidator, + address borrower, + uint repayAmount) external returns (uint); + function liquidateBorrowVerify( + address cTokenBorrowed, + address cTokenCollateral, + address liquidator, + address borrower, + uint repayAmount, + uint seizeTokens) external; + + function seizeAllowed( + address cTokenCollateral, + address cTokenBorrowed, + address liquidator, + address borrower, + uint seizeTokens) external returns (uint); + function seizeVerify( + address cTokenCollateral, + address cTokenBorrowed, + address liquidator, + address borrower, + uint seizeTokens) external; + + function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint); + function transferVerify(address cToken, address src, address dst, uint transferTokens) external; + + /*** Liquidity/Liquidation Calculations ***/ + + function liquidateCalculateSeizeTokens( + address cTokenBorrowed, + address cTokenCollateral, + uint repayAmount) external view returns (uint, uint); +} diff --git a/contracts/ComptrollerStorage.sol b/contracts/ComptrollerStorage.sol new file mode 100644 index 000000000..1218d3729 --- /dev/null +++ b/contracts/ComptrollerStorage.sol @@ -0,0 +1,55 @@ +pragma solidity ^0.5.8; + +import "./CToken.sol"; +import "./PriceOracle.sol"; + +contract UnitrollerAdminStorage { + /** + * @notice Administrator for this contract + */ + address public admin; + + /** + * @notice Pending administrator for this contract + */ + address public pendingAdmin; + + /** + * @notice Active brains of Unitroller + */ + address public comptrollerImplementation; + + /** + * @notice Pending brains of Unitroller + */ + address public pendingComptrollerImplementation; +} + +contract ComptrollerV1Storage is UnitrollerAdminStorage { + + /** + * @notice Oracle which gives the price of any given asset + */ + PriceOracle public oracle; + + /** + * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow + */ + uint public closeFactorMantissa; + + /** + * @notice Multiplier representing the discount on collateral that a liquidator receives + */ + uint public liquidationIncentiveMantissa; + + /** + * @notice Max number of assets a single account can participate in (borrow or use as collateral) + */ + uint public maxAssets; + + /** + * @notice Per-account mapping of "assets you are in", capped by maxAssets + */ + mapping(address => CToken[]) public accountAssets; + +} diff --git a/contracts/EIP20Interface.sol b/contracts/EIP20Interface.sol new file mode 100644 index 000000000..522e17b5f --- /dev/null +++ b/contracts/EIP20Interface.sol @@ -0,0 +1,59 @@ +pragma solidity ^0.5.8; + +/** + * @title ERC 20 Token Standard Interface + * https://eips.ethereum.org/EIPS/eip-20 + */ +interface EIP20Interface { + + /** + * @notice Get the total number of tokens in circulation + * @return The supply of tokens + */ + function totalSupply() external view returns (uint256); + + /** + * @notice Gets the balance of the specified address + * @param owner The address from which the balance will be retrieved + * @return The balance + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @notice Transfer `amount` tokens from `msg.sender` to `dst` + * @param dst The address of the destination account + * @param amount The number of tokens to transfer + * @return Whether or not the transfer succeeded + */ + function transfer(address dst, uint256 amount) external returns (bool success); + + /** + * @notice Transfer `amount` tokens from `src` to `dst` + * @param src The address of the source account + * @param dst The address of the destination account + * @param amount The number of tokens to transfer + * @return Whether or not the transfer succeeded + */ + function transferFrom(address src, address dst, uint256 amount) external returns (bool success); + + /** + * @notice Approve `spender` to transfer up to `amount` from `src` + * @dev This will overwrite the approval amount for `spender` + * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) + * @param spender The address of the account which may transfer tokens + * @param amount The number of tokens that are approved (-1 means infinite) + * @return Whether or not the approval succeeded + */ + function approve(address spender, uint256 amount) external returns (bool success); + + /** + * @notice Get the current allowance from `owner` for `spender` + * @param owner The address of the account which owns the tokens to be spent + * @param spender The address of the account which may transfer tokens + * @return The number of tokens allowed to be spent (-1 means infinite) + */ + function allowance(address owner, address spender) external view returns (uint256 remaining); + + event Transfer(address indexed from, address indexed to, uint256 amount); + event Approval(address indexed owner, address indexed spender, uint256 amount); +} diff --git a/contracts/EIP20NonStandardInterface.sol b/contracts/EIP20NonStandardInterface.sol new file mode 100644 index 000000000..1abbcb4c8 --- /dev/null +++ b/contracts/EIP20NonStandardInterface.sol @@ -0,0 +1,70 @@ +pragma solidity ^0.5.8; + +/** + * @title EIP20NonStandardInterface + * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` + * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca + */ +interface EIP20NonStandardInterface { + + /** + * @notice Get the total number of tokens in circulation + * @return The supply of tokens + */ + function totalSupply() external view returns (uint256); + + /** + * @notice Gets the balance of the specified address + * @param owner The address from which the balance will be retrieved + * @return The balance + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /// + /// !!!!!!!!!!!!!! + /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification + /// !!!!!!!!!!!!!! + /// + + /** + * @notice Transfer `amount` tokens from `msg.sender` to `dst` + * @param dst The address of the destination account + * @param amount The number of tokens to transfer + */ + function transfer(address dst, uint256 amount) external; + + /// + /// !!!!!!!!!!!!!! + /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification + /// !!!!!!!!!!!!!! + /// + + /** + * @notice Transfer `amount` tokens from `src` to `dst` + * @param src The address of the source account + * @param dst The address of the destination account + * @param amount The number of tokens to transfer + */ + function transferFrom(address src, address dst, uint256 amount) external; + + /** + * @notice Approve `spender` to transfer up to `amount` from `src` + * @dev This will overwrite the approval amount for `spender` + * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) + * @param spender The address of the account which may transfer tokens + * @param amount The number of tokens that are approved + * @return Whether or not the approval succeeded + */ + function approve(address spender, uint256 amount) external returns (bool success); + + /** + * @notice Get the current allowance from `owner` for `spender` + * @param owner The address of the account which owns the tokens to be spent + * @param spender The address of the account which may transfer tokens + * @return The number of tokens allowed to be spent + */ + function allowance(address owner, address spender) external view returns (uint256 remaining); + + event Transfer(address indexed from, address indexed to, uint256 amount); + event Approval(address indexed owner, address indexed spender, uint256 amount); +} diff --git a/contracts/ErrorReporter.sol b/contracts/ErrorReporter.sol new file mode 100644 index 000000000..ab646813f --- /dev/null +++ b/contracts/ErrorReporter.sol @@ -0,0 +1,204 @@ +pragma solidity ^0.5.8; + +contract ComptrollerErrorReporter { + enum Error { + NO_ERROR, + UNAUTHORIZED, + COMPTROLLER_MISMATCH, + INSUFFICIENT_SHORTFALL, + INSUFFICIENT_LIQUIDITY, + INVALID_CLOSE_FACTOR, + INVALID_COLLATERAL_FACTOR, + INVALID_LIQUIDATION_INCENTIVE, + MARKET_NOT_ENTERED, + MARKET_NOT_LISTED, + MARKET_ALREADY_LISTED, + MATH_ERROR, + NONZERO_BORROW_BALANCE, + PRICE_ERROR, + REJECTION, + SNAPSHOT_ERROR, + TOO_MANY_ASSETS, + TOO_MUCH_REPAY + } + + enum FailureInfo { + ACCEPT_ADMIN_PENDING_ADMIN_CHECK, + ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, + EXIT_MARKET_BALANCE_OWED, + EXIT_MARKET_REJECTION, + SET_CLOSE_FACTOR_OWNER_CHECK, + SET_CLOSE_FACTOR_VALIDATION, + SET_COLLATERAL_FACTOR_OWNER_CHECK, + SET_COLLATERAL_FACTOR_NO_EXISTS, + SET_COLLATERAL_FACTOR_VALIDATION, + SET_COLLATERAL_FACTOR_WITHOUT_PRICE, + SET_IMPLEMENTATION_OWNER_CHECK, + SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, + SET_LIQUIDATION_INCENTIVE_VALIDATION, + SET_MAX_ASSETS_OWNER_CHECK, + SET_PENDING_ADMIN_OWNER_CHECK, + SET_PENDING_IMPLEMENTATION_OWNER_CHECK, + SET_PRICE_ORACLE_OWNER_CHECK, + SUPPORT_MARKET_EXISTS, + SUPPORT_MARKET_OWNER_CHECK, + ZUNUSED + } + + /** + * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary + * contract-specific code that enables us to report opaque error codes from upgradeable contracts. + **/ + event Failure(uint error, uint info, uint detail); + + /** + * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator + */ + function fail(Error err, FailureInfo info) internal returns (uint) { + emit Failure(uint(err), uint(info), 0); + + return uint(err); + } + + /** + * @dev use this when reporting an opaque error from an upgradeable collaborator contract + */ + function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) { + emit Failure(uint(err), uint(info), opaqueError); + + return uint(err); + } +} + +contract TokenErrorReporter { + enum Error { + NO_ERROR, + UNAUTHORIZED, + BAD_INPUT, + COMPTROLLER_REJECTION, + COMPTROLLER_CALCULATION_ERROR, + INTEREST_RATE_MODEL_ERROR, + INVALID_ACCOUNT_PAIR, + INVALID_CLOSE_AMOUNT_REQUESTED, + INVALID_COLLATERAL_FACTOR, + MATH_ERROR, + MARKET_NOT_FRESH, + MARKET_NOT_LISTED, + TOKEN_INSUFFICIENT_ALLOWANCE, + TOKEN_INSUFFICIENT_BALANCE, + TOKEN_INSUFFICIENT_CASH, + TOKEN_TRANSFER_IN_FAILED, + TOKEN_TRANSFER_OUT_FAILED + } + + /* + * Note: FailureInfo (but not Error) is kept in alphabetical order + * This is because FailureInfo grows significantly faster, and + * the order of Error has some meaning, while the order of FailureInfo + * is entirely arbitrary. + */ + enum FailureInfo { + ACCEPT_ADMIN_PENDING_ADMIN_CHECK, + ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, + ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, + ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, + ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, + ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, + ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, + BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, + BORROW_ACCRUE_INTEREST_FAILED, + BORROW_CASH_NOT_AVAILABLE, + BORROW_FRESHNESS_CHECK, + BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, + BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, + BORROW_MARKET_NOT_LISTED, + BORROW_COMPTROLLER_REJECTION, + LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, + LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, + LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, + LIQUIDATE_COMPTROLLER_REJECTION, + LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, + LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, + LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, + LIQUIDATE_FRESHNESS_CHECK, + LIQUIDATE_LIQUIDATOR_IS_BORROWER, + LIQUIDATE_REPAY_BORROW_FRESH_FAILED, + LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, + LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, + LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, + LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, + LIQUIDATE_SEIZE_TOO_MUCH, + MINT_ACCRUE_INTEREST_FAILED, + MINT_COMPTROLLER_REJECTION, + MINT_EXCHANGE_CALCULATION_FAILED, + MINT_EXCHANGE_RATE_READ_FAILED, + MINT_FRESHNESS_CHECK, + MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, + MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, + MINT_TRANSFER_IN_FAILED, + MINT_TRANSFER_IN_NOT_POSSIBLE, + REDEEM_ACCRUE_INTEREST_FAILED, + REDEEM_COMPTROLLER_REJECTION, + REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, + REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, + REDEEM_EXCHANGE_RATE_READ_FAILED, + REDEEM_FRESHNESS_CHECK, + REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, + REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, + REDEEM_TRANSFER_OUT_NOT_POSSIBLE, + REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, + REDUCE_RESERVES_ADMIN_CHECK, + REDUCE_RESERVES_CASH_NOT_AVAILABLE, + REDUCE_RESERVES_FRESH_CHECK, + REDUCE_RESERVES_VALIDATION, + REPAY_BEHALF_ACCRUE_INTEREST_FAILED, + REPAY_BORROW_ACCRUE_INTEREST_FAILED, + REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, + REPAY_BORROW_COMPTROLLER_REJECTION, + REPAY_BORROW_FRESHNESS_CHECK, + REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, + REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, + REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, + SET_COLLATERAL_FACTOR_OWNER_CHECK, + SET_COLLATERAL_FACTOR_VALIDATION, + SET_COMPTROLLER_OWNER_CHECK, + SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, + SET_INTEREST_RATE_MODEL_FRESH_CHECK, + SET_INTEREST_RATE_MODEL_OWNER_CHECK, + SET_MAX_ASSETS_OWNER_CHECK, + SET_ORACLE_MARKET_NOT_LISTED, + SET_PENDING_ADMIN_OWNER_CHECK, + SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, + SET_RESERVE_FACTOR_ADMIN_CHECK, + SET_RESERVE_FACTOR_FRESH_CHECK, + SET_RESERVE_FACTOR_BOUNDS_CHECK, + TRANSFER_COMPTROLLER_REJECTION, + TRANSFER_NOT_ALLOWED, + TRANSFER_NOT_ENOUGH, + TRANSFER_TOO_MUCH + } + + /** + * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary + * contract-specific code that enables us to report opaque error codes from upgradeable contracts. + **/ + event Failure(uint error, uint info, uint detail); + + /** + * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator + */ + function fail(Error err, FailureInfo info) internal returns (uint) { + emit Failure(uint(err), uint(info), 0); + + return uint(err); + } + + /** + * @dev use this when reporting an opaque error from an upgradeable collaborator contract + */ + function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) { + emit Failure(uint(err), uint(info), opaqueError); + + return uint(err); + } +} diff --git a/contracts/Exponential.sol b/contracts/Exponential.sol new file mode 100644 index 000000000..4320ca01d --- /dev/null +++ b/contracts/Exponential.sol @@ -0,0 +1,226 @@ +pragma solidity ^0.5.8; + +import "./CarefulMath.sol"; + +/** + * @title Exponential module for storing fixed-decision decimals + * @author Compound + * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. + * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: + * `Exp({mantissa: 5100000000000000000})`. + */ +contract Exponential is CarefulMath { + uint constant expScale = 1e18; + uint constant halfExpScale = expScale/2; + uint constant mantissaOne = expScale; + + struct Exp { + uint mantissa; + } + + /** + * @dev Creates an exponential from numerator and denominator values. + * Note: Returns an error if (`num` * 10e18) > MAX_INT, + * or if `denom` is zero. + */ + function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) { + (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); + if (err0 != MathError.NO_ERROR) { + return (err0, Exp({mantissa: 0})); + } + + (MathError err1, uint rational) = divUInt(scaledNumerator, denom); + if (err1 != MathError.NO_ERROR) { + return (err1, Exp({mantissa: 0})); + } + + return (MathError.NO_ERROR, Exp({mantissa: rational})); + } + + /** + * @dev Adds two exponentials, returning a new exponential. + */ + function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { + (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); + + return (error, Exp({mantissa: result})); + } + + /** + * @dev Subtracts two exponentials, returning a new exponential. + */ + function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { + (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); + + return (error, Exp({mantissa: result})); + } + + /** + * @dev Multiply an Exp by a scalar, returning a new Exp. + */ + function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { + (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); + if (err0 != MathError.NO_ERROR) { + return (err0, Exp({mantissa: 0})); + } + + return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); + } + + /** + * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. + */ + function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) { + (MathError err, Exp memory product) = mulScalar(a, scalar); + if (err != MathError.NO_ERROR) { + return (err, 0); + } + + return (MathError.NO_ERROR, truncate(product)); + } + + /** + * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. + */ + function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) { + (MathError err, Exp memory product) = mulScalar(a, scalar); + if (err != MathError.NO_ERROR) { + return (err, 0); + } + + return addUInt(truncate(product), addend); + } + + /** + * @dev Divide an Exp by a scalar, returning a new Exp. + */ + function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { + (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); + if (err0 != MathError.NO_ERROR) { + return (err0, Exp({mantissa: 0})); + } + + return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); + } + + /** + * @dev Divide a scalar by an Exp, returning a new Exp. + */ + function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) { + /* + We are doing this as: + getExp(mulUInt(expScale, scalar), divisor.mantissa) + + How it works: + Exp = a / b; + Scalar = s; + `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` + */ + (MathError err0, uint numerator) = mulUInt(expScale, scalar); + if (err0 != MathError.NO_ERROR) { + return (err0, Exp({mantissa: 0})); + } + return getExp(numerator, divisor.mantissa); + } + + /** + * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. + */ + function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) { + (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); + if (err != MathError.NO_ERROR) { + return (err, 0); + } + + return (MathError.NO_ERROR, truncate(fraction)); + } + + /** + * @dev Multiplies two exponentials, returning a new exponential. + */ + function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { + + (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); + if (err0 != MathError.NO_ERROR) { + return (err0, Exp({mantissa: 0})); + } + + // We add half the scale before dividing so that we get rounding instead of truncation. + // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 + // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. + (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); + if (err1 != MathError.NO_ERROR) { + return (err1, Exp({mantissa: 0})); + } + + (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); + // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. + assert(err2 == MathError.NO_ERROR); + + return (MathError.NO_ERROR, Exp({mantissa: product})); + } + + /** + * @dev Multiplies two exponentials given their mantissas, returning a new exponential. + */ + function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) { + return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); + } + + /** + * @dev Multiplies three exponentials, returning a new exponential. + */ + function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) { + (MathError err, Exp memory ab) = mulExp(a, b); + if (err != MathError.NO_ERROR) { + return (err, ab); + } + return mulExp(ab, c); + } + + /** + * @dev Divides two exponentials, returning a new exponential. + * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, + * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) + */ + function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { + return getExp(a.mantissa, b.mantissa); + } + + /** + * @dev Truncates the given exp to a whole number value. + * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 + */ + function truncate(Exp memory exp) pure internal returns (uint) { + // Note: We are not using careful math here as we're performing a division that cannot fail + return exp.mantissa / expScale; + } + + /** + * @dev Checks if first Exp is less than second Exp. + */ + function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { + return left.mantissa < right.mantissa; //TODO: Add some simple tests and this in another PR yo. + } + + /** + * @dev Checks if left Exp <= right Exp. + */ + function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { + return left.mantissa <= right.mantissa; + } + + /** + * @dev Checks if left Exp > right Exp. + */ + function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { + return left.mantissa > right.mantissa; + } + + /** + * @dev returns true if Exp is exactly zero + */ + function isZeroExp(Exp memory value) pure internal returns (bool) { + return value.mantissa == 0; + } +} diff --git a/contracts/InterestRateModel.sol b/contracts/InterestRateModel.sol new file mode 100644 index 000000000..8ab34b586 --- /dev/null +++ b/contracts/InterestRateModel.sol @@ -0,0 +1,29 @@ +pragma solidity ^0.5.8; + +/** + * @title The Compound InterestRateModel Interface + * @author Compound + * @notice Any interest rate model should derive from this contract. + * @dev These functions are specifically not marked `pure` as implementations of this + * contract may read from storage variables. + */ +interface InterestRateModel { + /** + * @notice Gets the current borrow interest rate based on the given asset, total cash, total borrows + * and total reserves. + * @dev The return value should be scaled by 1e18, thus a return value of + * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. + * @param cash The total cash of the underlying asset in the CToken + * @param borrows The total borrows of the underlying asset in the CToken + * @param reserves The total reserves of the underlying asset in the CToken + * @return Success or failure and the borrow interest rate per block scaled by 10e18 + */ + function getBorrowRate(uint cash, uint borrows, uint reserves) external view returns (uint, uint); + + /** + * @notice Marker function used for light validation when updating the interest rate model of a market + * @dev Marker function used for light validation when updating the interest rate model of a market. Implementations should simply return true. + * @return Success or failure + */ + function isInterestRateModel() external view returns (bool); +} \ No newline at end of file diff --git a/contracts/Maximillion.sol b/contracts/Maximillion.sol new file mode 100644 index 000000000..cfca4b2aa --- /dev/null +++ b/contracts/Maximillion.sol @@ -0,0 +1,49 @@ +pragma solidity ^0.5.8; + +import "./CEther.sol"; + +/** + * @title Compound's Maximillion Contract + * @author Compound + */ +contract Maximillion { + /** + * @notice The default cEther market to repay in + */ + CEther public cEther; + + /** + * @notice Construct a Maximillion to repay max in a CEther market + */ + constructor(CEther cEther_) public { + cEther = cEther_; + } + + /** + * @notice msg.sender sends Ether to repay an account's borrow in the cEther market + * @dev The provided Ether is applied towards the borrow balance, any excess is refunded + * @param borrower The address of the borrower account to repay on behalf of + * @return The initial borrows before the repay + */ + function repayBehalf(address borrower) public payable { + return repayBehalfExplicit(borrower, cEther); + } + + /** + * @notice msg.sender sends Ether to repay an account's borrow in a cEther market + * @dev The provided Ether is applied towards the borrow balance, any excess is refunded + * @param borrower The address of the borrower account to repay on behalf of + * @param cEther_ The address of the cEther contract to repay in + * @return The initial borrows before the repay + */ + function repayBehalfExplicit(address borrower, CEther cEther_) public payable { + uint received = msg.value; + uint borrows = cEther_.borrowBalanceCurrent(borrower); + if (received > borrows) { + cEther_.repayBorrowBehalf.value(borrows)(borrower); + msg.sender.transfer(received - borrows); + } else { + cEther_.repayBorrowBehalf.value(received)(borrower); + } + } +} diff --git a/contracts/PriceOracle.sol b/contracts/PriceOracle.sol new file mode 100644 index 000000000..6fbcb1ab4 --- /dev/null +++ b/contracts/PriceOracle.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.5.8; + +import "./CToken.sol"; + +interface PriceOracle { + /** + * @notice Indicator that this is a PriceOracle contract (for inspection) + */ + function isPriceOracle() external pure returns (bool); + + /** + * @notice Get the underlying price of a cToken asset + * @param cToken The cToken to get the underlying price of + * @return The underlying asset price mantissa (scaled by 1e18). + * Zero means the price is unavailable. + */ + function getUnderlyingPrice(CToken cToken) external view returns (uint); +} diff --git a/contracts/PriceOracleProxy.sol b/contracts/PriceOracleProxy.sol new file mode 100644 index 000000000..a506673e6 --- /dev/null +++ b/contracts/PriceOracleProxy.sol @@ -0,0 +1,88 @@ +pragma solidity ^0.5.8; + +import "./CErc20.sol"; +import "./CToken.sol"; +import "./PriceOracle.sol"; +import "./Comptroller.sol"; + +interface V1PriceOracleInterface { + function assetPrices(address asset) external view returns (uint); +} + +contract PriceOracleProxy is PriceOracle { + /** + * @notice The v1 price oracle, which will continue to serve prices + * prices for v1 assets + */ + V1PriceOracleInterface public v1PriceOracle; + + /** + * @notice The active comptroller, which will be checked for listing status + * to short circuit and return 0 for unlisted assets. + * + * @dev Listed markets are not part of the comptroller interface used by + * cTokens, so we assumena an instance of v1 comptroller.sol instead + */ + Comptroller public comptroller; + + /** + * @notice address of the cEther contract, which has a constant price + */ + address public cEtherAddress; + + /** + * @notice address of the cUSDC contract, which we hand pick a key for + */ + address public cUsdcAddress; + + /** + * @notice address of the USDC contract, which we hand pick a key for + */ + address constant usdcOracleKey = address(1); + + /** + * @notice Indicator that this is a PriceOracle contract (for inspection) + */ + bool public constant isPriceOracle = true; + + /** + * @param comptroller_ The address of the active comptroller, which will + * be consulted for market listing status. + * @param v1PriceOracle_ The address of the v1 price oracle, which will + * continue to operate and hold prices for collateral assets. + * @param cEtherAddress_ The address of the cEther contract, which will + * return a constant 1e18, since all prices relative to ether + */ + constructor(address comptroller_, address v1PriceOracle_, address cEtherAddress_, address cUsdcAddress_) public { + comptroller = Comptroller(comptroller_); + v1PriceOracle = V1PriceOracleInterface(v1PriceOracle_); + cEtherAddress = cEtherAddress_; + cUsdcAddress = cUsdcAddress_; + } + + /** + * @notice Get the underlying price of a listed cToken asset + * @param cToken The cToken to get the underlying price of + * @return The underlying asset price mantissa (scaled by 1e18). + * Zero means the price is unavailable. + */ + function getUnderlyingPrice(CToken cToken) public view returns (uint) { + address cTokenAddress = address(cToken); + (bool isListed, ) = comptroller.markets(cTokenAddress); + + if (!isListed) { + // not listed, worthless + return 0; + } else if (cTokenAddress == cEtherAddress) { + // ether always worth 1 + return 1e18; + } else if (cTokenAddress == cUsdcAddress) { + // read from hand picked key + return v1PriceOracle.assetPrices(usdcOracleKey); + } else { + // read from v1 oracle + address underlying = CErc20(cTokenAddress).underlying(); + return v1PriceOracle.assetPrices(underlying); + } + } +} diff --git a/contracts/ReentrancyGuard.sol b/contracts/ReentrancyGuard.sol new file mode 100644 index 000000000..6bf885d0f --- /dev/null +++ b/contracts/ReentrancyGuard.sol @@ -0,0 +1,32 @@ +pragma solidity ^0.5.8; + +/** + * @title Helps contracts guard against reentrancy attacks. + * @author Remco Bloemen , Eenae + * @dev If you mark a function `nonReentrant`, you should also + * mark it `external`. + */ +contract ReentrancyGuard { + /// @dev counter to allow mutex lock with only one SSTORE operation + uint256 private _guardCounter; + + constructor () internal { + // The counter starts at one to prevent changing it from zero to a non-zero + // value, which is a more expensive operation. + _guardCounter = 1; + } + + /** + * @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 make it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + _guardCounter += 1; + uint256 localCounter = _guardCounter; + _; + require(localCounter == _guardCounter, "re-entered"); + } +} diff --git a/contracts/SimplePriceOracle.sol b/contracts/SimplePriceOracle.sol new file mode 100644 index 000000000..afe627a9f --- /dev/null +++ b/contracts/SimplePriceOracle.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.5.8; + +import "./PriceOracle.sol"; +import "./CErc20.sol"; + +contract SimplePriceOracle is PriceOracle { + mapping(address => uint) prices; + bool public constant isPriceOracle = true; + + function getUnderlyingPrice(CToken cToken) public view returns (uint) { + return prices[address(CErc20(address(cToken)).underlying())]; + } + + function setUnderlyingPrice(CToken cToken, uint underlyingPriceMantissa) public { + prices[address(CErc20(address(cToken)).underlying())] = underlyingPriceMantissa; + } + + function setDirectPrice(address a, uint price) public { + prices[a] = price; + } + + // v1 price oracle interface for use as backing of proxy + function assetPrices(address asset) external view returns (uint) { + return prices[asset]; + } +} diff --git a/contracts/Unitroller.sol b/contracts/Unitroller.sol new file mode 100644 index 000000000..1bb0d7368 --- /dev/null +++ b/contracts/Unitroller.sol @@ -0,0 +1,152 @@ +pragma solidity ^0.5.8; + +import "./ErrorReporter.sol"; +import "./ComptrollerStorage.sol"; +/** + * @title ComptrollerCore + * @dev storage for the comptroller will be at this address, and + * cTokens should reference this contract rather than a deployed implementation if + * + */ +contract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter { + + /** + * @notice Emitted when pendingComptrollerImplementation is changed + */ + event NewPendingImplementation(address oldPendingImplementation, address newPendingImplementation); + + /** + * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated + */ + event NewImplementation(address oldImplementation, address newImplementation); + + /** + * @notice Emitted when pendingAdmin is changed + */ + event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); + + /** + * @notice Emitted when pendingAdmin is accepted, which means admin is updated + */ + event NewAdmin(address oldAdmin, address newAdmin); + + constructor() public { + // Set admin to caller + admin = msg.sender; + } + + /*** Admin Functions ***/ + function _setPendingImplementation(address newPendingImplementation) public returns (uint) { + + if (msg.sender != admin) { + return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK); + } + + address oldPendingImplementation = pendingComptrollerImplementation; + + pendingComptrollerImplementation = newPendingImplementation; + + emit NewPendingImplementation(oldPendingImplementation, pendingComptrollerImplementation); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation + * @dev Admin function for new implementation to accept it's role as implementation + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _acceptImplementation() public returns (uint) { + // Check caller is pendingImplementation and pendingImplementation ≠ address(0) + if (msg.sender != pendingComptrollerImplementation || pendingComptrollerImplementation == address(0)) { + return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK); + } + + // Save current values for inclusion in log + address oldImplementation = comptrollerImplementation; + address oldPendingImplementation = pendingComptrollerImplementation; + + comptrollerImplementation = pendingComptrollerImplementation; + + pendingComptrollerImplementation = address(0); + + emit NewImplementation(oldImplementation, comptrollerImplementation); + emit NewPendingImplementation(oldPendingImplementation, pendingComptrollerImplementation); + + return uint(Error.NO_ERROR); + } + + + /** + * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. + * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. + * @param newPendingAdmin New pending admin. + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + * + * TODO: Should we add a second arg to verify, like a checksum of `newAdmin` address? + */ + function _setPendingAdmin(address newPendingAdmin) public returns (uint) { + // Check caller = admin + if (msg.sender != admin) { + return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK); + } + + // Save current value, if any, for inclusion in log + address oldPendingAdmin = pendingAdmin; + + // Store pendingAdmin with value newPendingAdmin + pendingAdmin = newPendingAdmin; + + // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) + emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin + * @dev Admin function for pending admin to accept role and update admin + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _acceptAdmin() public returns (uint) { + // Check caller is pendingAdmin and pendingAdmin ≠ address(0) + if (msg.sender != pendingAdmin || msg.sender == address(0)) { + return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK); + } + + // Save current values for inclusion in log + address oldAdmin = admin; + address oldPendingAdmin = pendingAdmin; + + // Store admin with value pendingAdmin + admin = pendingAdmin; + + // Clear the pending value + pendingAdmin = address(0); + + emit NewAdmin(oldAdmin, admin); + emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); + + return uint(Error.NO_ERROR); + } + + /** + * @dev Delegates execution to an implementation contract. + * It returns to the external caller whatever the implementation returns + * or forwards reverts. + */ + function () payable external { + // delegate all other functions to current implementation + (bool success, ) = comptrollerImplementation.delegatecall(msg.data); + + // solium-disable-next-line security/no-inline-assembly + assembly { + let free_mem_ptr := mload(0x40) + returndatacopy(free_mem_ptr, 0, returndatasize) + + switch success + case 0 { revert(free_mem_ptr, returndatasize) } + default { return(free_mem_ptr, returndatasize) } + } + } +} diff --git a/contracts/WhitePaperInterestRateModel.sol b/contracts/WhitePaperInterestRateModel.sol new file mode 100644 index 000000000..7a7c5b464 --- /dev/null +++ b/contracts/WhitePaperInterestRateModel.sol @@ -0,0 +1,133 @@ +pragma solidity ^0.5.8; + +import "./Exponential.sol"; +import "./InterestRateModel.sol"; + +/** + * @title The Compound Standard Interest Rate Model with pluggable constants + * @author Compound + * @notice See Section 2.4 of the Compound Whitepaper + */ +contract WhitePaperInterestRateModel is InterestRateModel, Exponential { + /** + * @notice Indicator that this is an InterestRateModel contract (for inspection) + */ + bool public constant isInterestRateModel = true; + + /** + * @notice The multiplier of utilization rate that gives the slope of the interest rate + */ + uint public multiplier; + + /** + * @notice The base interest rate which is the y-intercept when utilization rate is 0 + */ + uint public baseRate; + + /** + * @notice The approximate number of blocks per year that is assumed by the interest rate model + */ + uint public constant blocksPerYear = 2102400; + + constructor(uint baseRate_, uint multiplier_) public { + baseRate = baseRate_; + multiplier = multiplier_; + } + + enum IRError { + NO_ERROR, + FAILED_TO_ADD_CASH_PLUS_BORROWS, + FAILED_TO_GET_EXP, + FAILED_TO_MUL_UTILIZATION_RATE, + FAILED_TO_ADD_BASE_RATE + } + + /* + * @dev Calculates the utilization rate (borrows / (cash + borrows)) as an Exp + */ + function getUtilizationRate(uint cash, uint borrows) pure internal returns (IRError, Exp memory) { + if (borrows == 0) { + // Utilization rate is zero when there's no borrows + return (IRError.NO_ERROR, Exp({mantissa: 0})); + } + + (MathError err0, uint cashPlusBorrows) = addUInt(cash, borrows); + if (err0 != MathError.NO_ERROR) { + return (IRError.FAILED_TO_ADD_CASH_PLUS_BORROWS, Exp({mantissa: 0})); + } + + (MathError err1, Exp memory utilizationRate) = getExp(borrows, cashPlusBorrows); + if (err1 != MathError.NO_ERROR) { + return (IRError.FAILED_TO_GET_EXP, Exp({mantissa: 0})); + } + + return (IRError.NO_ERROR, utilizationRate); + } + + /* + * @dev Calculates the utilization and borrow rates for use by getBorrowRate function + */ + function getUtilizationAndAnnualBorrowRate(uint cash, uint borrows) view internal returns (IRError, Exp memory, Exp memory) { + (IRError err0, Exp memory utilizationRate) = getUtilizationRate(cash, borrows); + if (err0 != IRError.NO_ERROR) { + return (err0, Exp({mantissa: 0}), Exp({mantissa: 0})); + } + + // Borrow Rate is 5% + UtilizationRate * 45% (baseRate + UtilizationRate * multiplier); + // 45% of utilizationRate, is `rate * 45 / 100` + (MathError err1, Exp memory utilizationRateMuled) = mulScalar(utilizationRate, multiplier); + // `mulScalar` only overflows when the product is >= 2^256. + // utilizationRate is a real number on the interval [0,1], which means that + // utilizationRate.mantissa is in the interval [0e18,1e18], which means that 45 times + // that is in the interval [0e18,45e18]. That interval has no intersection with 2^256, and therefore + // this can never overflow for the standard rates. + if (err1 != MathError.NO_ERROR) { + return (IRError.FAILED_TO_MUL_UTILIZATION_RATE, Exp({mantissa: 0}), Exp({mantissa: 0})); + } + + (MathError err2, Exp memory utilizationRateScaled) = divScalar(utilizationRateMuled, mantissaOne); + // 100 is a constant, and therefore cannot be zero, which is the only error case of divScalar. + assert(err2 == MathError.NO_ERROR); + + // Add the 5% for (5% + 45% * Ua) + (MathError err3, Exp memory annualBorrowRate) = addExp(utilizationRateScaled, Exp({mantissa: baseRate})); + // `addExp` only fails when the addition of mantissas overflow. + // As per above, utilizationRateMuled is capped at 45e18, + // and utilizationRateScaled is capped at 4.5e17. mantissaFivePercent = 0.5e17, and thus the addition + // is capped at 5e17, which is less than 2^256. This only applies to the standard rates + if (err3 != MathError.NO_ERROR) { + return (IRError.FAILED_TO_ADD_BASE_RATE, Exp({mantissa: 0}), Exp({mantissa: 0})); + } + + return (IRError.NO_ERROR, utilizationRate, annualBorrowRate); + } + + /** + * @notice Gets the current borrow interest rate based on the given asset, total cash, total borrows + * and total reserves. + * @dev The return value should be scaled by 1e18, thus a return value of + * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*. + * @param cash The total cash of the underlying asset in the CToken + * @param borrows The total borrows of the underlying asset in the CToken + * @param _reserves The total reserves of the underlying asset in the CToken + * @return Success or failure and the borrow interest rate per block scaled by 10e18 + */ + function getBorrowRate(uint cash, uint borrows, uint _reserves) public view returns (uint, uint) { + _reserves; // pragma ignore unused argument + + (IRError err0, Exp memory _utilizationRate, Exp memory annualBorrowRate) = getUtilizationAndAnnualBorrowRate(cash, borrows); + if (err0 != IRError.NO_ERROR) { + return (uint(err0), 0); + } + + // And then divide down by blocks per year. + (MathError err1, Exp memory borrowRate) = divScalar(annualBorrowRate, blocksPerYear); // basis points * blocks per year + // divScalar only fails when divisor is zero. This is clearly not the case. + assert(err1 == MathError.NO_ERROR); + + _utilizationRate; // pragma ignore unused variable + + // Note: mantissa is the rate scaled 1e18, which matches the expected result + return (uint(IRError.NO_ERROR), borrowRate.mantissa); + } +} diff --git a/docs/CompoundProtocol.pdf b/docs/CompoundProtocol.pdf new file mode 100644 index 000000000..64daadc53 Binary files /dev/null and b/docs/CompoundProtocol.pdf differ diff --git a/docs/CompoundWhitepaper.pdf b/docs/CompoundWhitepaper.pdf new file mode 100644 index 000000000..625754948 Binary files /dev/null and b/docs/CompoundWhitepaper.pdf differ diff --git a/migrations/.gitkeep b/migrations/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/networks/.gitkeep b/networks/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/networks/README.md b/networks/README.md new file mode 100644 index 000000000..06c673c15 --- /dev/null +++ b/networks/README.md @@ -0,0 +1,26 @@ +## Network Configuration + +This folder contains the configuration for given networks (e.g. `rinkeby.json` is the configuration for the Rinkeby test-net). These configuration files are meant to be used to configure external applications (like dApps) and thus contain a base set of information that may be useful (such as the address the Comptroller and a list of cToken markets). These configuration files are auto-generated when doing local development. + +Structure +--------- + +```json +{ + "Contracts": { + "MoneyMarket": "0x{address}", + "Migrations": "0x{address}", + "PriceOracle": "0x{address}", + "InterestRateModel": "0x{address}" + }, + "Tokens": { + "{SYM}": { + "name": "{Full Name}", + "symbol": "{SYM}", + "decimals": 18, + "address": "0x{address}", + "supported": true + } + } +} +``` \ No newline at end of file diff --git a/networks/goerli-abi.json b/networks/goerli-abi.json new file mode 100644 index 000000000..1694872a4 --- /dev/null +++ b/networks/goerli-abi.json @@ -0,0 +1,13952 @@ +{ + "ZRX": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "cUSDC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "PriceOracle": [ + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "underlyingPriceMantissa", + "type": "uint256" + } + ], + "name": "setUnderlyingPrice", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x127ffda0" + }, + { + "constant": true, + "inputs": [ + { + "name": "asset", + "type": "address" + } + ], + "name": "assetPrices", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5e9a523c" + }, + { + "constant": true, + "inputs": [], + "name": "isPriceOracle", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x66331bba" + }, + { + "constant": true, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "getUnderlyingPrice", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfc57d4df" + } + ], + "PriceOracleProxy": [ + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": true, + "inputs": [], + "name": "isPriceOracle", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x66331bba" + }, + { + "constant": true, + "inputs": [], + "name": "cEtherAddress", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xde836acf" + }, + { + "constant": true, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "getUnderlyingPrice", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfc57d4df" + }, + { + "constant": true, + "inputs": [], + "name": "v1PriceOracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe10c98d" + }, + { + "inputs": [ + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "v1PriceOracle_", + "type": "address" + }, + { + "name": "cEtherAddress_", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "Maximillion": [ + { + "constant": true, + "inputs": [], + "name": "cEther", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x19b68c00" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "cEther_", + "type": "address" + } + ], + "name": "repayBehalfExplicit", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x367b7f05" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + } + ], + "name": "repayBehalf", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x9f35c3d5" + }, + { + "inputs": [ + { + "name": "cEther_", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "cDAI": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "DAI": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "StdComptroller": [ + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x007e3dd2" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x1ededc91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x24008a62" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x317b0b77" + }, + { + "constant": false, + "inputs": [ + { + "name": "unitroller", + "type": "address" + }, + { + "name": "_oracle", + "type": "address" + }, + { + "name": "_closeFactorMantissa", + "type": "uint256" + }, + { + "name": "_maxAssets", + "type": "uint256" + }, + { + "name": "reinitializing", + "type": "bool" + } + ], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x32000e00" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + }, + { + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x41c728b9" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x47ef3b3b" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x4ada90af" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4ef4c3e1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "_setLiquidationIncentive", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4fd42e17" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemAmount", + "type": "uint256" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x51dff989" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x55ee1fe1" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5c778605" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5ec88c79" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5fc7e71e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6a56947e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6d35bf91" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x7dc0d1d0" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "name": "isListed", + "type": "bool" + }, + { + "name": "collateralFactorMantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8e8f294b" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "cToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x929fe9a1" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x94b2294b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa76b3fda" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xabfceffc" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbdcdc258" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc2998238" + }, + { + "constant": true, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc488847b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd02f7351" + }, + { + "constant": false, + "inputs": [ + { + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "_setMaxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd9226ced" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xda3d454c" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdce15449" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCollateralFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe4028eee" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe8755446" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xeabe7d91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xede4edd0" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event", + "signature": "0xcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event", + "signature": "0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event", + "signature": "0xe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event", + "signature": "0x3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event", + "signature": "0x70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event", + "signature": "0xaeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldMaxAssets", + "type": "uint256" + }, + { + "indexed": false, + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "NewMaxAssets", + "type": "event", + "signature": "0x7093cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event", + "signature": "0xd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "Unitroller": [ + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc1e80334" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "_setPendingImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe992a041" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "NewPendingImplementation", + "type": "event", + "signature": "0xe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d815" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newImplementation", + "type": "address" + } + ], + "name": "NewImplementation", + "type": "event", + "signature": "0xd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "Comptroller": [ + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc1e80334" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "_setPendingImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe992a041" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "NewPendingImplementation", + "type": "event", + "signature": "0xe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d815" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newImplementation", + "type": "address" + } + ], + "name": "NewImplementation", + "type": "event", + "signature": "0xd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x007e3dd2" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x1ededc91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x24008a62" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x317b0b77" + }, + { + "constant": false, + "inputs": [ + { + "name": "unitroller", + "type": "address" + }, + { + "name": "_oracle", + "type": "address" + }, + { + "name": "_closeFactorMantissa", + "type": "uint256" + }, + { + "name": "_maxAssets", + "type": "uint256" + }, + { + "name": "reinitializing", + "type": "bool" + } + ], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x32000e00" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + }, + { + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x41c728b9" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x47ef3b3b" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x4ada90af" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4ef4c3e1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "_setLiquidationIncentive", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4fd42e17" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemAmount", + "type": "uint256" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x51dff989" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x55ee1fe1" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5c778605" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5ec88c79" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5fc7e71e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6a56947e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6d35bf91" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x7dc0d1d0" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "name": "isListed", + "type": "bool" + }, + { + "name": "collateralFactorMantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8e8f294b" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "cToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x929fe9a1" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x94b2294b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa76b3fda" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xabfceffc" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbdcdc258" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc2998238" + }, + { + "constant": true, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc488847b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd02f7351" + }, + { + "constant": false, + "inputs": [ + { + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "_setMaxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd9226ced" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xda3d454c" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdce15449" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCollateralFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe4028eee" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe8755446" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xeabe7d91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xede4edd0" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event", + "signature": "0xcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event", + "signature": "0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event", + "signature": "0xe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event", + "signature": "0x3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event", + "signature": "0x70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event", + "signature": "0xaeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldMaxAssets", + "type": "uint256" + }, + { + "indexed": false, + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "NewMaxAssets", + "type": "event", + "signature": "0x7093cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event", + "signature": "0xd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "cBAT": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "Base0bps_Slope2000bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "BAT": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "cETH": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [], + "name": "mint", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x1249c58b" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": false, + "inputs": [], + "name": "repayBorrow", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x4e4d9fea" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0xaae40a2a" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + } + ], + "name": "repayBorrowBehalf", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0xe5974619" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "Base500bps_Slope1200bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "Base200bps_Slope3000bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "cREP": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "WBTC": [ + { + "constant": true, + "inputs": [], + "name": "mintingFinished", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x05d2035b" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + } + ], + "name": "reclaimToken", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17ffc320" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [], + "name": "unpause", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3f4ba83a" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x40c10f19" + }, + { + "constant": false, + "inputs": [ + { + "name": "value", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x42966c68" + }, + { + "constant": false, + "inputs": [], + "name": "claimOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4e71e0c8" + }, + { + "constant": true, + "inputs": [], + "name": "paused", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5c975abb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x715018a6" + }, + { + "constant": false, + "inputs": [], + "name": "finishMinting", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x7d64bcb4" + }, + { + "constant": false, + "inputs": [], + "name": "pause", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x8456cb59" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8da5cb5b" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": true, + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe30c3978" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2fde38b" + }, + { + "anonymous": false, + "inputs": [], + "name": "Pause", + "type": "event", + "signature": "0x6985a02210a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff625" + }, + { + "anonymous": false, + "inputs": [], + "name": "Unpause", + "type": "event", + "signature": "0x7805862f689e2f13df9f062ff482ad3ad112aca9e0847911ed832e158c525b33" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "burner", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Burn", + "type": "event", + "signature": "0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885" + }, + { + "anonymous": false, + "inputs": [], + "name": "MintFinished", + "type": "event", + "signature": "0xae5184fba832cb2b1f702aca6117b8d265eaf03ad33eb133f19dde0f5920fa08" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "previousOwner", + "type": "address" + } + ], + "name": "OwnershipRenounced", + "type": "event", + "signature": "0xf8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c64820" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event", + "signature": "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "REP": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "cZRX": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "cWBTC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "USDC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ] +} \ No newline at end of file diff --git a/networks/goerli.json b/networks/goerli.json new file mode 100644 index 000000000..2b18cc67a --- /dev/null +++ b/networks/goerli.json @@ -0,0 +1,296 @@ +{ + "Contracts": { + "ZRX": "0x6c041606A9b4A449dF6B5FF7274B79a869616D65", + "cUSDC": "0xD9FFe966A831089981Bd1539503c9d3cb45E5AAb", + "PriceOracle": "0x9f8376931cd4c3c38C0128A77082ba40e8D4a8a1", + "PriceOracleProxy": "0x83047d759094cBc94df2DE8caF33C6C5990eE095", + "Maximillion": "0xcCb206b7b33F46cB0a8e55Bf1f173fe3e8661076", + "cDAI": "0xd9fd9E875c9C1d567825E431DD6Ed4f0e51aA8Bf", + "DAI": "0xB8C5995387c8086d0B496Bd54755d14D7cED8256", + "StdComptroller": "0xC2210dFFE9DE7eA7A7ed933EeE3e28ae6786b9f5", + "Unitroller": "0xe884DcC3167613A5D6A6EF96F90B74E411F32C8a", + "Comptroller": "0xe884DcC3167613A5D6A6EF96F90B74E411F32C8a", + "cBAT": "0xc31211101e6D98bEA24F1f32cbeBa3e9ac7c9749", + "Base0bps_Slope2000bps": "0x23E8731b39E46941f73951b7f39d921bFd6C2E05", + "BAT": "0x3e0d325ABA23E9562281D48b2Bd52594Db48CC18", + "cETH": "0x2B2aA9c7967eFAd4B73BFD8801333928806409A1", + "Base500bps_Slope1200bps": "0x63cFb6469408a64d6713C28231c8d90a609aeB23", + "Base200bps_Slope3000bps": "0x8cD09AF719A93fB3b52a05Dbc4eC0Fa559EEC9C2", + "cREP": "0x0812e50F3740b89899Ce889C2ab913eA2565f626", + "WBTC": "0xFD1853eb1391B094dd9DfAB566d94F8b6400316c", + "REP": "0x4308246f8806135d840c8C81bF658d58c0Fd295C", + "cZRX": "0xf412f4d0eE1D96eb486C6C2836bEDc4912bA294E", + "cWBTC": "0xe43d693C6d063BDF4A9681f9A6D9D1439344f4f7", + "USDC": "0x7Dc9912705FfDb928F62D9694fEfdD3a09F3eCD0" + }, + "Blocks": { + "ZRX": 924883, + "cUSDC": 924929, + "PriceOracle": 924871, + "PriceOracleProxy": 924948, + "Maximillion": 924932, + "cDAI": 924893, + "DAI": 924885, + "StdComptroller": 924875, + "Unitroller": 924873, + "cBAT": 924892, + "Base0bps_Slope2000bps": 924879, + "BAT": 924884, + "cETH": 924895, + "Base500bps_Slope1200bps": 924878, + "Base200bps_Slope3000bps": 924881, + "cREP": 924894, + "WBTC": 924889, + "REP": 924886, + "cZRX": 924891, + "cWBTC": 924931, + "USDC": 924887 + }, + "PriceOracle": { + "description": "Simple Price Oracle", + "address": "0x9f8376931cd4c3c38C0128A77082ba40e8D4a8a1" + }, + "Maximillion": { + "description": "Maximillion", + "cEtherAddress": "0x2B2aA9c7967eFAd4B73BFD8801333928806409A1", + "address": "0xcCb206b7b33F46cB0a8e55Bf1f173fe3e8661076" + }, + "Unitroller": { + "description": "Unitroller", + "address": "0xe884DcC3167613A5D6A6EF96F90B74E411F32C8a" + }, + "Comptroller": { + "StdComptroller": { + "address": "0xC2210dFFE9DE7eA7A7ed933EeE3e28ae6786b9f5", + "contract": "Comptroller", + "description": "Standard Comptroller Impl" + } + }, + "Constructors": { + "ZRX": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000002307800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a52580000000000000000000000000000000000000000000000000000000000", + "cUSDC": "0x0000000000000000000000007dc9912705ffdb928f62d9694fefdd3a09f3ecd0000000000000000000000000e884dcc3167613a5d6a6ef96f90b74e411f32c8a00000000000000000000000023e8731b39e46941f73951b7f39d921bfd6c2e050000000000000000000000000000000000000000000000000000b5e620f4800000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000016436f6d706f756e642055534420436f696e20f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000000000056355534443000000000000000000000000000000000000000000000000000000", + "PriceOracle": "0x", + "PriceOracleProxy": "0x000000000000000000000000e884dcc3167613a5d6a6ef96f90b74e411f32c8a0000000000000000000000009f8376931cd4c3c38c0128a77082ba40e8d4a8a10000000000000000000000002b2aa9c7967efad4b73bfd8801333928806409a1", + "Maximillion": "0x0000000000000000000000002b2aa9c7967efad4b73bfd8801333928806409a1", + "cDAI": "0x000000000000000000000000b8c5995387c8086d0b496bd54755d14d7ced8256000000000000000000000000e884dcc3167613a5d6a6ef96f90b74e411f32c8a00000000000000000000000063cfb6469408a64d6713c28231c8d90a609aeb23000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000011436f6d706f756e642044616920f09f938800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046344414900000000000000000000000000000000000000000000000000000000", + "DAI": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000003446169000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034441490000000000000000000000000000000000000000000000000000000000", + "StdComptroller": "0x", + "Unitroller": "0x", + "cBAT": "0x0000000000000000000000003e0d325aba23e9562281d48b2bd52594db48cc18000000000000000000000000e884dcc3167613a5d6a6ef96f90b74e411f32c8a0000000000000000000000008cd09af719a93fb3b52a05dbc4ec0fa559eec9c2000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000023436f6d706f756e6420426173696320417474656e74696f6e20546f6b656e20f09f9388000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046342415400000000000000000000000000000000000000000000000000000000", + "Base0bps_Slope2000bps": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c68af0bb140000", + "BAT": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000015426173696320417474656e74696f6e20546f6b656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000034241540000000000000000000000000000000000000000000000000000000000", + "cETH": "0x000000000000000000000000e884dcc3167613a5d6a6ef96f90b74e411f32c8a00000000000000000000000023e8731b39e46941f73951b7f39d921bfd6c2e05000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000013436f6d706f756e6420457468657220f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046345544800000000000000000000000000000000000000000000000000000000", + "Base500bps_Slope1200bps": "0x00000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000001aa535d3d0c0000", + "Base200bps_Slope3000bps": "0x00000000000000000000000000000000000000000000000000470de4df8200000000000000000000000000000000000000000000000000000429d069189e0000", + "cREP": "0x0000000000000000000000004308246f8806135d840c8c81bf658d58c0fd295c000000000000000000000000e884dcc3167613a5d6a6ef96f90b74e411f32c8a0000000000000000000000008cd09af719a93fb3b52a05dbc4ec0fa559eec9c2000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000013436f6d706f756e6420417567757220f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046352455000000000000000000000000000000000000000000000000000000000", + "WBTC": "0x", + "REP": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000005417567757200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035245500000000000000000000000000000000000000000000000000000000000", + "cZRX": "0x0000000000000000000000006c041606a9b4a449df6b5ff7274b79a869616d65000000000000000000000000e884dcc3167613a5d6a6ef96f90b74e411f32c8a0000000000000000000000008cd09af719a93fb3b52a05dbc4ec0fa559eec9c2000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010436f6d706f756e6420307820f09f9388000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004635a525800000000000000000000000000000000000000000000000000000000", + "cWBTC": "0x000000000000000000000000fd1853eb1391b094dd9dfab566d94f8b6400316c000000000000000000000000e884dcc3167613a5d6a6ef96f90b74e411f32c8a0000000000000000000000008cd09af719a93fb3b52a05dbc4ec0fa559eec9c200000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000019436f6d706f756e6420577261707065642042544320f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000056357425443000000000000000000000000000000000000000000000000000000", + "USDC": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000855534420436f696e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045553444300000000000000000000000000000000000000000000000000000000" + }, + "Tokens": { + "ZRX": { + "description": "Standard", + "name": "0x", + "symbol": "ZRX", + "decimals": 18, + "contract": "FaucetToken", + "address": "0x6c041606A9b4A449dF6B5FF7274B79a869616D65" + }, + "cUSDC": { + "name": "Compound USD Coin 📈", + "symbol": "cUSDC", + "decimals": 8, + "underlying": "0x7Dc9912705FfDb928F62D9694fEfdD3a09F3eCD0", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000", + "address": "0xD9FFe966A831089981Bd1539503c9d3cb45E5AAb" + }, + "cDAI": { + "name": "Compound Dai 📈", + "symbol": "cDAI", + "decimals": 8, + "underlying": "0xB8C5995387c8086d0B496Bd54755d14D7cED8256", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xd9fd9E875c9C1d567825E431DD6Ed4f0e51aA8Bf" + }, + "DAI": { + "description": "Standard", + "name": "Dai", + "symbol": "DAI", + "decimals": 18, + "contract": "FaucetToken", + "address": "0xB8C5995387c8086d0B496Bd54755d14D7cED8256" + }, + "cBAT": { + "name": "Compound Basic Attention Token 📈", + "symbol": "cBAT", + "decimals": 8, + "underlying": "0x3e0d325ABA23E9562281D48b2Bd52594Db48CC18", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xc31211101e6D98bEA24F1f32cbeBa3e9ac7c9749" + }, + "BAT": { + "description": "NonStandard", + "name": "Basic Attention Token", + "symbol": "BAT", + "decimals": 18, + "contract": "FaucetNonStandardToken", + "address": "0x3e0d325ABA23E9562281D48b2Bd52594Db48CC18" + }, + "cETH": { + "name": "Compound Ether 📈", + "symbol": "cETH", + "decimals": 8, + "underlying": "", + "contract": "CEther", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x2B2aA9c7967eFAd4B73BFD8801333928806409A1" + }, + "cREP": { + "name": "Compound Augur 📈", + "symbol": "cREP", + "decimals": 8, + "underlying": "0x4308246f8806135d840c8C81bF658d58c0Fd295C", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x0812e50F3740b89899Ce889C2ab913eA2565f626" + }, + "WBTC": { + "description": "WBTC", + "name": "Wrapped BTC", + "symbol": "WBTC", + "decimals": 8, + "contract": "WBTCToken", + "address": "0xFD1853eb1391B094dd9DfAB566d94F8b6400316c" + }, + "REP": { + "description": "Standard", + "name": "Augur", + "symbol": "REP", + "decimals": 18, + "contract": "FaucetToken", + "address": "0x4308246f8806135d840c8C81bF658d58c0Fd295C" + }, + "cZRX": { + "name": "Compound 0x 📈", + "symbol": "cZRX", + "decimals": 8, + "underlying": "0x6c041606A9b4A449dF6B5FF7274B79a869616D65", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xf412f4d0eE1D96eb486C6C2836bEDc4912bA294E" + }, + "cWBTC": { + "name": "Compound Wrapped BTC 📈", + "symbol": "cWBTC", + "decimals": 8, + "underlying": "0xFD1853eb1391B094dd9DfAB566d94F8b6400316c", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "20000000000000000", + "address": "0xe43d693C6d063BDF4A9681f9A6D9D1439344f4f7" + }, + "USDC": { + "description": "Standard", + "name": "USD Coin", + "symbol": "USDC", + "decimals": 6, + "contract": "FaucetToken", + "address": "0x7Dc9912705FfDb928F62D9694fEfdD3a09F3eCD0" + } + }, + "cTokens": { + "cZRX": { + "name": "Compound 0x 📈", + "symbol": "cZRX", + "decimals": 8, + "underlying": "0x6c041606A9b4A449dF6B5FF7274B79a869616D65", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xf412f4d0eE1D96eb486C6C2836bEDc4912bA294E" + }, + "cBAT": { + "name": "Compound Basic Attention Token 📈", + "symbol": "cBAT", + "decimals": 8, + "underlying": "0x3e0d325ABA23E9562281D48b2Bd52594Db48CC18", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xc31211101e6D98bEA24F1f32cbeBa3e9ac7c9749" + }, + "cDAI": { + "name": "Compound Dai 📈", + "symbol": "cDAI", + "decimals": 8, + "underlying": "0xB8C5995387c8086d0B496Bd54755d14D7cED8256", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xd9fd9E875c9C1d567825E431DD6Ed4f0e51aA8Bf" + }, + "cREP": { + "name": "Compound Augur 📈", + "symbol": "cREP", + "decimals": 8, + "underlying": "0x4308246f8806135d840c8C81bF658d58c0Fd295C", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x0812e50F3740b89899Ce889C2ab913eA2565f626" + }, + "cETH": { + "name": "Compound Ether 📈", + "symbol": "cETH", + "decimals": 8, + "underlying": "", + "contract": "CEther", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x2B2aA9c7967eFAd4B73BFD8801333928806409A1" + }, + "cUSDC": { + "name": "Compound USD Coin 📈", + "symbol": "cUSDC", + "decimals": 8, + "underlying": "0x7Dc9912705FfDb928F62D9694fEfdD3a09F3eCD0", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000", + "address": "0xD9FFe966A831089981Bd1539503c9d3cb45E5AAb" + }, + "cWBTC": { + "name": "Compound Wrapped BTC 📈", + "symbol": "cWBTC", + "decimals": 8, + "underlying": "0xFD1853eb1391B094dd9DfAB566d94F8b6400316c", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "20000000000000000", + "address": "0xe43d693C6d063BDF4A9681f9A6D9D1439344f4f7" + } + }, + "InterestRateModel": { + "Base500bps_Slope1200bps": { + "name": "Base500bps_Slope1200bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=50000000000000000 multiplier=120000000000000000", + "base": "50000000000000000", + "slope": "120000000000000000", + "address": "0x63cFb6469408a64d6713C28231c8d90a609aeB23" + }, + "Base0bps_Slope2000bps": { + "name": "Base0bps_Slope2000bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=0 multiplier=200000000000000000", + "base": "0", + "slope": "200000000000000000", + "address": "0x23E8731b39E46941f73951b7f39d921bFd6C2E05" + }, + "Base200bps_Slope3000bps": { + "name": "Base200bps_Slope3000bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=20000000000000000 multiplier=300000000000000000", + "base": "20000000000000000", + "slope": "300000000000000000", + "address": "0x8cD09AF719A93fB3b52a05Dbc4eC0Fa559EEC9C2" + } + } +} \ No newline at end of file diff --git a/networks/kovan-abi.json b/networks/kovan-abi.json new file mode 100644 index 000000000..1694872a4 --- /dev/null +++ b/networks/kovan-abi.json @@ -0,0 +1,13952 @@ +{ + "ZRX": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "cUSDC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "PriceOracle": [ + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "underlyingPriceMantissa", + "type": "uint256" + } + ], + "name": "setUnderlyingPrice", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x127ffda0" + }, + { + "constant": true, + "inputs": [ + { + "name": "asset", + "type": "address" + } + ], + "name": "assetPrices", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5e9a523c" + }, + { + "constant": true, + "inputs": [], + "name": "isPriceOracle", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x66331bba" + }, + { + "constant": true, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "getUnderlyingPrice", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfc57d4df" + } + ], + "PriceOracleProxy": [ + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": true, + "inputs": [], + "name": "isPriceOracle", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x66331bba" + }, + { + "constant": true, + "inputs": [], + "name": "cEtherAddress", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xde836acf" + }, + { + "constant": true, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "getUnderlyingPrice", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfc57d4df" + }, + { + "constant": true, + "inputs": [], + "name": "v1PriceOracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe10c98d" + }, + { + "inputs": [ + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "v1PriceOracle_", + "type": "address" + }, + { + "name": "cEtherAddress_", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "Maximillion": [ + { + "constant": true, + "inputs": [], + "name": "cEther", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x19b68c00" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "cEther_", + "type": "address" + } + ], + "name": "repayBehalfExplicit", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x367b7f05" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + } + ], + "name": "repayBehalf", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x9f35c3d5" + }, + { + "inputs": [ + { + "name": "cEther_", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "cDAI": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "DAI": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "StdComptroller": [ + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x007e3dd2" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x1ededc91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x24008a62" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x317b0b77" + }, + { + "constant": false, + "inputs": [ + { + "name": "unitroller", + "type": "address" + }, + { + "name": "_oracle", + "type": "address" + }, + { + "name": "_closeFactorMantissa", + "type": "uint256" + }, + { + "name": "_maxAssets", + "type": "uint256" + }, + { + "name": "reinitializing", + "type": "bool" + } + ], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x32000e00" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + }, + { + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x41c728b9" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x47ef3b3b" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x4ada90af" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4ef4c3e1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "_setLiquidationIncentive", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4fd42e17" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemAmount", + "type": "uint256" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x51dff989" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x55ee1fe1" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5c778605" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5ec88c79" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5fc7e71e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6a56947e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6d35bf91" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x7dc0d1d0" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "name": "isListed", + "type": "bool" + }, + { + "name": "collateralFactorMantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8e8f294b" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "cToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x929fe9a1" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x94b2294b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa76b3fda" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xabfceffc" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbdcdc258" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc2998238" + }, + { + "constant": true, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc488847b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd02f7351" + }, + { + "constant": false, + "inputs": [ + { + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "_setMaxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd9226ced" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xda3d454c" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdce15449" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCollateralFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe4028eee" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe8755446" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xeabe7d91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xede4edd0" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event", + "signature": "0xcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event", + "signature": "0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event", + "signature": "0xe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event", + "signature": "0x3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event", + "signature": "0x70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event", + "signature": "0xaeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldMaxAssets", + "type": "uint256" + }, + { + "indexed": false, + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "NewMaxAssets", + "type": "event", + "signature": "0x7093cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event", + "signature": "0xd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "Unitroller": [ + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc1e80334" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "_setPendingImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe992a041" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "NewPendingImplementation", + "type": "event", + "signature": "0xe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d815" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newImplementation", + "type": "address" + } + ], + "name": "NewImplementation", + "type": "event", + "signature": "0xd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "Comptroller": [ + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc1e80334" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "_setPendingImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe992a041" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "NewPendingImplementation", + "type": "event", + "signature": "0xe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d815" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newImplementation", + "type": "address" + } + ], + "name": "NewImplementation", + "type": "event", + "signature": "0xd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x007e3dd2" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x1ededc91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x24008a62" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x317b0b77" + }, + { + "constant": false, + "inputs": [ + { + "name": "unitroller", + "type": "address" + }, + { + "name": "_oracle", + "type": "address" + }, + { + "name": "_closeFactorMantissa", + "type": "uint256" + }, + { + "name": "_maxAssets", + "type": "uint256" + }, + { + "name": "reinitializing", + "type": "bool" + } + ], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x32000e00" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + }, + { + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x41c728b9" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x47ef3b3b" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x4ada90af" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4ef4c3e1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "_setLiquidationIncentive", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4fd42e17" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemAmount", + "type": "uint256" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x51dff989" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x55ee1fe1" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5c778605" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5ec88c79" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5fc7e71e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6a56947e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6d35bf91" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x7dc0d1d0" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "name": "isListed", + "type": "bool" + }, + { + "name": "collateralFactorMantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8e8f294b" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "cToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x929fe9a1" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x94b2294b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa76b3fda" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xabfceffc" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbdcdc258" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc2998238" + }, + { + "constant": true, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc488847b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd02f7351" + }, + { + "constant": false, + "inputs": [ + { + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "_setMaxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd9226ced" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xda3d454c" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdce15449" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCollateralFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe4028eee" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe8755446" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xeabe7d91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xede4edd0" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event", + "signature": "0xcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event", + "signature": "0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event", + "signature": "0xe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event", + "signature": "0x3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event", + "signature": "0x70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event", + "signature": "0xaeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldMaxAssets", + "type": "uint256" + }, + { + "indexed": false, + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "NewMaxAssets", + "type": "event", + "signature": "0x7093cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event", + "signature": "0xd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "cBAT": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "Base0bps_Slope2000bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "BAT": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "cETH": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [], + "name": "mint", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x1249c58b" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": false, + "inputs": [], + "name": "repayBorrow", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x4e4d9fea" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0xaae40a2a" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + } + ], + "name": "repayBorrowBehalf", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0xe5974619" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "Base500bps_Slope1200bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "Base200bps_Slope3000bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "cREP": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "WBTC": [ + { + "constant": true, + "inputs": [], + "name": "mintingFinished", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x05d2035b" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + } + ], + "name": "reclaimToken", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17ffc320" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [], + "name": "unpause", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3f4ba83a" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x40c10f19" + }, + { + "constant": false, + "inputs": [ + { + "name": "value", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x42966c68" + }, + { + "constant": false, + "inputs": [], + "name": "claimOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4e71e0c8" + }, + { + "constant": true, + "inputs": [], + "name": "paused", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5c975abb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x715018a6" + }, + { + "constant": false, + "inputs": [], + "name": "finishMinting", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x7d64bcb4" + }, + { + "constant": false, + "inputs": [], + "name": "pause", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x8456cb59" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8da5cb5b" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": true, + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe30c3978" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2fde38b" + }, + { + "anonymous": false, + "inputs": [], + "name": "Pause", + "type": "event", + "signature": "0x6985a02210a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff625" + }, + { + "anonymous": false, + "inputs": [], + "name": "Unpause", + "type": "event", + "signature": "0x7805862f689e2f13df9f062ff482ad3ad112aca9e0847911ed832e158c525b33" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "burner", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Burn", + "type": "event", + "signature": "0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885" + }, + { + "anonymous": false, + "inputs": [], + "name": "MintFinished", + "type": "event", + "signature": "0xae5184fba832cb2b1f702aca6117b8d265eaf03ad33eb133f19dde0f5920fa08" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "previousOwner", + "type": "address" + } + ], + "name": "OwnershipRenounced", + "type": "event", + "signature": "0xf8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c64820" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event", + "signature": "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "REP": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "cZRX": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "cWBTC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "USDC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ] +} \ No newline at end of file diff --git a/networks/kovan.json b/networks/kovan.json new file mode 100644 index 000000000..e96a24792 --- /dev/null +++ b/networks/kovan.json @@ -0,0 +1,296 @@ +{ + "Contracts": { + "ZRX": "0x7CfF490cfb21B130619055Ba62665ECCDCc12C17", + "cUSDC": "0xDff375162cfE7D77473C1BEC4560dEDE974E138c", + "PriceOracle": "0x5C46CBeEa623dAD6e08560ee487d5aC5afD57997", + "PriceOracleProxy": "0x0314440102f1b2be6b4Dd797371fc2E42d8F9c5f", + "Maximillion": "0x2B536482a01E620eE111747F8334B395a42A555E", + "cDAI": "0x0A1e4D0B5c71B955c0a5993023fc48bA6E380496", + "DAI": "0xbF7A7169562078c96f0eC1A8aFD6aE50f12e5A99", + "StdComptroller": "0x04396A3e673980dAfa3BCC1EfD3632f075E57447", + "Unitroller": "0x142D11CB90a2b40f7d0C55ed1804988DfC316fAe", + "Comptroller": "0x142D11CB90a2b40f7d0C55ed1804988DfC316fAe", + "cBAT": "0xB5E5D0F8C0cbA267CD3D7035d6AdC8eBA7Df7Cdd", + "Base0bps_Slope2000bps": "0xb081cf57B1e422B3E627544Ec95992CBe8Eaf9cb", + "BAT": "0xddea378A6dDC8AfeC82C36E9b0078826bf9e68B6", + "cETH": "0xD83F707f003A1f0B1535028AB356FCE2667ab855", + "Base500bps_Slope1200bps": "0x5dEA9621f23e79003eCC294b4cc1e4c9362dFECc", + "Base200bps_Slope3000bps": "0xe622DB19D5bf1F4e61Dd57FB11FE887100E5e59E", + "cREP": "0x8a9447df1FB47209D36204e6D56767a33bf20f9f", + "WBTC": "0x19787bcF63E228a6669d905E90aF397DCA313CFC", + "REP": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa", + "cZRX": "0x9636246bf34E688c6652Af544418B38eB51D2c43", + "cWBTC": "0x189CA88bE39C9c1B8c8dd437F5ff1DB1f584b14b", + "USDC": "0x6e894660985207feb7cf89Faf048998c71E8EE89" + }, + "Blocks": { + "ZRX": 12162495, + "cUSDC": 12162506, + "PriceOracle": 12162487, + "PriceOracleProxy": 12162521, + "Maximillion": 12162508, + "cDAI": 12162503, + "DAI": 12162497, + "StdComptroller": 12162489, + "Unitroller": 12162488, + "cBAT": 12162502, + "Base0bps_Slope2000bps": 12162493, + "BAT": 12162496, + "cETH": 12162505, + "Base500bps_Slope1200bps": 12162492, + "Base200bps_Slope3000bps": 12162494, + "cREP": 12162504, + "WBTC": 12162500, + "REP": 12162498, + "cZRX": 12162501, + "cWBTC": 12162507, + "USDC": 12162499 + }, + "PriceOracle": { + "description": "Simple Price Oracle", + "address": "0x5C46CBeEa623dAD6e08560ee487d5aC5afD57997" + }, + "Maximillion": { + "description": "Maximillion", + "cEtherAddress": "0xD83F707f003A1f0B1535028AB356FCE2667ab855", + "address": "0x2B536482a01E620eE111747F8334B395a42A555E" + }, + "Unitroller": { + "description": "Unitroller", + "address": "0x142D11CB90a2b40f7d0C55ed1804988DfC316fAe" + }, + "Comptroller": { + "StdComptroller": { + "address": "0x04396A3e673980dAfa3BCC1EfD3632f075E57447", + "contract": "Comptroller", + "description": "Standard Comptroller Impl" + } + }, + "Constructors": { + "ZRX": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000002307800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a52580000000000000000000000000000000000000000000000000000000000", + "cUSDC": "0x0000000000000000000000006e894660985207feb7cf89faf048998c71e8ee89000000000000000000000000142d11cb90a2b40f7d0c55ed1804988dfc316fae000000000000000000000000b081cf57b1e422b3e627544ec95992cbe8eaf9cb0000000000000000000000000000000000000000000000000000b5e620f4800000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000016436f6d706f756e642055534420436f696e20f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000000000056355534443000000000000000000000000000000000000000000000000000000", + "PriceOracle": "0x", + "PriceOracleProxy": "0x000000000000000000000000142d11cb90a2b40f7d0c55ed1804988dfc316fae0000000000000000000000005c46cbeea623dad6e08560ee487d5ac5afd57997000000000000000000000000d83f707f003a1f0b1535028ab356fce2667ab855", + "Maximillion": "0x000000000000000000000000d83f707f003a1f0b1535028ab356fce2667ab855", + "cDAI": "0x000000000000000000000000bf7a7169562078c96f0ec1a8afd6ae50f12e5a99000000000000000000000000142d11cb90a2b40f7d0c55ed1804988dfc316fae0000000000000000000000005dea9621f23e79003ecc294b4cc1e4c9362dfecc000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000011436f6d706f756e642044616920f09f938800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046344414900000000000000000000000000000000000000000000000000000000", + "DAI": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000003446169000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034441490000000000000000000000000000000000000000000000000000000000", + "StdComptroller": "0x", + "Unitroller": "0x", + "cBAT": "0x000000000000000000000000ddea378a6ddc8afec82c36e9b0078826bf9e68b6000000000000000000000000142d11cb90a2b40f7d0c55ed1804988dfc316fae000000000000000000000000e622db19d5bf1f4e61dd57fb11fe887100e5e59e000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000023436f6d706f756e6420426173696320417474656e74696f6e20546f6b656e20f09f9388000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046342415400000000000000000000000000000000000000000000000000000000", + "Base0bps_Slope2000bps": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c68af0bb140000", + "BAT": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000015426173696320417474656e74696f6e20546f6b656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000034241540000000000000000000000000000000000000000000000000000000000", + "cETH": "0x000000000000000000000000142d11cb90a2b40f7d0c55ed1804988dfc316fae000000000000000000000000b081cf57b1e422b3e627544ec95992cbe8eaf9cb000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000013436f6d706f756e6420457468657220f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046345544800000000000000000000000000000000000000000000000000000000", + "Base500bps_Slope1200bps": "0x00000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000001aa535d3d0c0000", + "Base200bps_Slope3000bps": "0x00000000000000000000000000000000000000000000000000470de4df8200000000000000000000000000000000000000000000000000000429d069189e0000", + "cREP": "0x0000000000000000000000005592ec0cfb4dbc12d3ab100b257153436a1f0fea000000000000000000000000142d11cb90a2b40f7d0c55ed1804988dfc316fae000000000000000000000000e622db19d5bf1f4e61dd57fb11fe887100e5e59e000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000013436f6d706f756e6420417567757220f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046352455000000000000000000000000000000000000000000000000000000000", + "WBTC": "0x", + "REP": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000005417567757200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035245500000000000000000000000000000000000000000000000000000000000", + "cZRX": "0x0000000000000000000000007cff490cfb21b130619055ba62665eccdcc12c17000000000000000000000000142d11cb90a2b40f7d0c55ed1804988dfc316fae000000000000000000000000e622db19d5bf1f4e61dd57fb11fe887100e5e59e000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010436f6d706f756e6420307820f09f9388000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004635a525800000000000000000000000000000000000000000000000000000000", + "cWBTC": "0x00000000000000000000000019787bcf63e228a6669d905e90af397dca313cfc000000000000000000000000142d11cb90a2b40f7d0c55ed1804988dfc316fae000000000000000000000000e622db19d5bf1f4e61dd57fb11fe887100e5e59e00000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000019436f6d706f756e6420577261707065642042544320f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000056357425443000000000000000000000000000000000000000000000000000000", + "USDC": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000855534420436f696e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045553444300000000000000000000000000000000000000000000000000000000" + }, + "Tokens": { + "ZRX": { + "description": "Standard", + "name": "0x", + "symbol": "ZRX", + "decimals": 18, + "contract": "FaucetToken", + "address": "0x7CfF490cfb21B130619055Ba62665ECCDCc12C17" + }, + "cUSDC": { + "name": "Compound USD Coin 📈", + "symbol": "cUSDC", + "decimals": 8, + "underlying": "0x6e894660985207feb7cf89Faf048998c71E8EE89", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000", + "address": "0xDff375162cfE7D77473C1BEC4560dEDE974E138c" + }, + "cDAI": { + "name": "Compound Dai 📈", + "symbol": "cDAI", + "decimals": 8, + "underlying": "0xbF7A7169562078c96f0eC1A8aFD6aE50f12e5A99", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x0A1e4D0B5c71B955c0a5993023fc48bA6E380496" + }, + "DAI": { + "description": "Standard", + "name": "Dai", + "symbol": "DAI", + "decimals": 18, + "contract": "FaucetToken", + "address": "0xbF7A7169562078c96f0eC1A8aFD6aE50f12e5A99" + }, + "cBAT": { + "name": "Compound Basic Attention Token 📈", + "symbol": "cBAT", + "decimals": 8, + "underlying": "0xddea378A6dDC8AfeC82C36E9b0078826bf9e68B6", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xB5E5D0F8C0cbA267CD3D7035d6AdC8eBA7Df7Cdd" + }, + "BAT": { + "description": "NonStandard", + "name": "Basic Attention Token", + "symbol": "BAT", + "decimals": 18, + "contract": "FaucetNonStandardToken", + "address": "0xddea378A6dDC8AfeC82C36E9b0078826bf9e68B6" + }, + "cETH": { + "name": "Compound Ether 📈", + "symbol": "cETH", + "decimals": 8, + "underlying": "", + "contract": "CEther", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xD83F707f003A1f0B1535028AB356FCE2667ab855" + }, + "cREP": { + "name": "Compound Augur 📈", + "symbol": "cREP", + "decimals": 8, + "underlying": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x8a9447df1FB47209D36204e6D56767a33bf20f9f" + }, + "WBTC": { + "description": "WBTC", + "name": "Wrapped BTC", + "symbol": "WBTC", + "decimals": 8, + "contract": "WBTCToken", + "address": "0x19787bcF63E228a6669d905E90aF397DCA313CFC" + }, + "REP": { + "description": "Standard", + "name": "Augur", + "symbol": "REP", + "decimals": 18, + "contract": "FaucetToken", + "address": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa" + }, + "cZRX": { + "name": "Compound 0x 📈", + "symbol": "cZRX", + "decimals": 8, + "underlying": "0x7CfF490cfb21B130619055Ba62665ECCDCc12C17", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x9636246bf34E688c6652Af544418B38eB51D2c43" + }, + "cWBTC": { + "name": "Compound Wrapped BTC 📈", + "symbol": "cWBTC", + "decimals": 8, + "underlying": "0x19787bcF63E228a6669d905E90aF397DCA313CFC", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "20000000000000000", + "address": "0x189CA88bE39C9c1B8c8dd437F5ff1DB1f584b14b" + }, + "USDC": { + "description": "Standard", + "name": "USD Coin", + "symbol": "USDC", + "decimals": 6, + "contract": "FaucetToken", + "address": "0x6e894660985207feb7cf89Faf048998c71E8EE89" + } + }, + "cTokens": { + "cZRX": { + "name": "Compound 0x 📈", + "symbol": "cZRX", + "decimals": 8, + "underlying": "0x7CfF490cfb21B130619055Ba62665ECCDCc12C17", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x9636246bf34E688c6652Af544418B38eB51D2c43" + }, + "cBAT": { + "name": "Compound Basic Attention Token 📈", + "symbol": "cBAT", + "decimals": 8, + "underlying": "0xddea378A6dDC8AfeC82C36E9b0078826bf9e68B6", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xB5E5D0F8C0cbA267CD3D7035d6AdC8eBA7Df7Cdd" + }, + "cDAI": { + "name": "Compound Dai 📈", + "symbol": "cDAI", + "decimals": 8, + "underlying": "0xbF7A7169562078c96f0eC1A8aFD6aE50f12e5A99", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x0A1e4D0B5c71B955c0a5993023fc48bA6E380496" + }, + "cREP": { + "name": "Compound Augur 📈", + "symbol": "cREP", + "decimals": 8, + "underlying": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x8a9447df1FB47209D36204e6D56767a33bf20f9f" + }, + "cETH": { + "name": "Compound Ether 📈", + "symbol": "cETH", + "decimals": 8, + "underlying": "", + "contract": "CEther", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xD83F707f003A1f0B1535028AB356FCE2667ab855" + }, + "cUSDC": { + "name": "Compound USD Coin 📈", + "symbol": "cUSDC", + "decimals": 8, + "underlying": "0x6e894660985207feb7cf89Faf048998c71E8EE89", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000", + "address": "0xDff375162cfE7D77473C1BEC4560dEDE974E138c" + }, + "cWBTC": { + "name": "Compound Wrapped BTC 📈", + "symbol": "cWBTC", + "decimals": 8, + "underlying": "0x19787bcF63E228a6669d905E90aF397DCA313CFC", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "20000000000000000", + "address": "0x189CA88bE39C9c1B8c8dd437F5ff1DB1f584b14b" + } + }, + "InterestRateModel": { + "Base500bps_Slope1200bps": { + "name": "Base500bps_Slope1200bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=50000000000000000 multiplier=120000000000000000", + "base": "50000000000000000", + "slope": "120000000000000000", + "address": "0x5dEA9621f23e79003eCC294b4cc1e4c9362dFECc" + }, + "Base0bps_Slope2000bps": { + "name": "Base0bps_Slope2000bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=0 multiplier=200000000000000000", + "base": "0", + "slope": "200000000000000000", + "address": "0xb081cf57B1e422B3E627544Ec95992CBe8Eaf9cb" + }, + "Base200bps_Slope3000bps": { + "name": "Base200bps_Slope3000bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=20000000000000000 multiplier=300000000000000000", + "base": "20000000000000000", + "slope": "300000000000000000", + "address": "0xe622DB19D5bf1F4e61Dd57FB11FE887100E5e59E" + } + } +} \ No newline at end of file diff --git a/networks/mainnet-abi.json b/networks/mainnet-abi.json new file mode 100644 index 000000000..dcaf6a272 --- /dev/null +++ b/networks/mainnet-abi.json @@ -0,0 +1,13598 @@ +{ + "cUSDC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "StandardInterestRateModel": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event" + }, + { + "constant": true, + "inputs": [ + { + "name": "_asset", + "type": "address" + }, + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + } + ], + "name": "getSupplyRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_asset", + "type": "address" + }, + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ], + "Migrations": [ + { + "constant": true, + "inputs": [], + "name": "last_completed_migration", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "constant": false, + "inputs": [ + { + "name": "completed", + "type": "uint256" + } + ], + "name": "setCompleted", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "new_address", + "type": "address" + } + ], + "name": "upgrade", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "PriceOracle": [ + { + "constant": true, + "inputs": [], + "name": "anchorAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "maxSwingMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "_assetPrices", + "outputs": [ + { + "name": "mantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAnchorAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "numBlocksPerPeriod", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "readers", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "paused", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "anchors", + "outputs": [ + { + "name": "period", + "type": "uint256" + }, + { + "name": "priceMantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "poster", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "pendingAnchors", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "maxSwing", + "outputs": [ + { + "name": "mantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "name": "_poster", + "type": "address" + }, + { + "name": "addr0", + "type": "address" + }, + { + "name": "reader0", + "type": "address" + }, + { + "name": "addr1", + "type": "address" + }, + { + "name": "reader1", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "msgSender", + "type": "address" + }, + { + "indexed": false, + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "OracleFailure", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "anchorAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "name": "oldScaledPrice", + "type": "uint256" + }, + { + "indexed": false, + "name": "newScaledPrice", + "type": "uint256" + } + ], + "name": "NewPendingAnchor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "name": "previousPriceMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "requestedPriceMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newPriceMantissa", + "type": "uint256" + } + ], + "name": "PricePosted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "name": "requestedPriceMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "anchorPriceMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "cappedPriceMantissa", + "type": "uint256" + } + ], + "name": "CappedPricePosted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "newState", + "type": "bool" + } + ], + "name": "SetPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAnchorAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAnchorAdmin", + "type": "address" + } + ], + "name": "NewPendingAnchorAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAnchorAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAnchorAdmin", + "type": "address" + } + ], + "name": "NewAnchorAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "name": "asset", + "type": "address" + }, + { + "name": "newScaledPrice", + "type": "uint256" + } + ], + "name": "_setPendingAnchor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "requestedState", + "type": "bool" + } + ], + "name": "_setPaused", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAnchorAdmin", + "type": "address" + } + ], + "name": "_setPendingAnchorAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAnchorAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "asset", + "type": "address" + } + ], + "name": "assetPrices", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "asset", + "type": "address" + } + ], + "name": "getPrice", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "asset", + "type": "address" + }, + { + "name": "requestedPriceMantissa", + "type": "uint256" + } + ], + "name": "setPrice", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "assets", + "type": "address[]" + }, + { + "name": "requestedPriceMantissas", + "type": "uint256[]" + } + ], + "name": "setPrices", + "outputs": [ + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "PriceOracleProxy": [ + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": true, + "inputs": [], + "name": "isPriceOracle", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x66331bba" + }, + { + "constant": true, + "inputs": [], + "name": "cEtherAddress", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xde836acf" + }, + { + "constant": true, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "getUnderlyingPrice", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfc57d4df" + }, + { + "constant": true, + "inputs": [], + "name": "v1PriceOracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe10c98d" + }, + { + "inputs": [ + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "v1PriceOracle_", + "type": "address" + }, + { + "name": "cEtherAddress_", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "Maximillion": [ + { + "constant": true, + "inputs": [], + "name": "cEther", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x19b68c00" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "cEther_", + "type": "address" + } + ], + "name": "repayBehalfExplicit", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x367b7f05" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + } + ], + "name": "repayBehalf", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x9f35c3d5" + }, + { + "inputs": [ + { + "name": "cEther_", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "cDAI": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "StdComptroller": [ + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x007e3dd2" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x1ededc91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x24008a62" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x317b0b77" + }, + { + "constant": false, + "inputs": [ + { + "name": "unitroller", + "type": "address" + }, + { + "name": "_oracle", + "type": "address" + }, + { + "name": "_closeFactorMantissa", + "type": "uint256" + }, + { + "name": "_maxAssets", + "type": "uint256" + }, + { + "name": "reinitializing", + "type": "bool" + } + ], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x32000e00" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + }, + { + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x41c728b9" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x47ef3b3b" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x4ada90af" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4ef4c3e1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "_setLiquidationIncentive", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4fd42e17" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemAmount", + "type": "uint256" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x51dff989" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x55ee1fe1" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5c778605" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5ec88c79" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5fc7e71e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6a56947e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6d35bf91" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x7dc0d1d0" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "name": "isListed", + "type": "bool" + }, + { + "name": "collateralFactorMantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8e8f294b" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "cToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x929fe9a1" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x94b2294b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa76b3fda" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xabfceffc" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbdcdc258" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc2998238" + }, + { + "constant": true, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc488847b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd02f7351" + }, + { + "constant": false, + "inputs": [ + { + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "_setMaxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd9226ced" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xda3d454c" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdce15449" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCollateralFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe4028eee" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe8755446" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xeabe7d91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xede4edd0" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event", + "signature": "0xcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event", + "signature": "0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event", + "signature": "0xe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event", + "signature": "0x3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event", + "signature": "0x70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event", + "signature": "0xaeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldMaxAssets", + "type": "uint256" + }, + { + "indexed": false, + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "NewMaxAssets", + "type": "event", + "signature": "0x7093cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event", + "signature": "0xd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "Unitroller": [ + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc1e80334" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "_setPendingImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe992a041" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "NewPendingImplementation", + "type": "event", + "signature": "0xe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d815" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newImplementation", + "type": "address" + } + ], + "name": "NewImplementation", + "type": "event", + "signature": "0xd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "Comptroller": [ + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc1e80334" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "_setPendingImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe992a041" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "NewPendingImplementation", + "type": "event", + "signature": "0xe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d815" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newImplementation", + "type": "address" + } + ], + "name": "NewImplementation", + "type": "event", + "signature": "0xd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x007e3dd2" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x1ededc91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x24008a62" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x317b0b77" + }, + { + "constant": false, + "inputs": [ + { + "name": "unitroller", + "type": "address" + }, + { + "name": "_oracle", + "type": "address" + }, + { + "name": "_closeFactorMantissa", + "type": "uint256" + }, + { + "name": "_maxAssets", + "type": "uint256" + }, + { + "name": "reinitializing", + "type": "bool" + } + ], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x32000e00" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + }, + { + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x41c728b9" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x47ef3b3b" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x4ada90af" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4ef4c3e1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "_setLiquidationIncentive", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4fd42e17" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemAmount", + "type": "uint256" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x51dff989" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x55ee1fe1" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5c778605" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5ec88c79" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5fc7e71e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6a56947e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6d35bf91" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x7dc0d1d0" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "name": "isListed", + "type": "bool" + }, + { + "name": "collateralFactorMantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8e8f294b" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "cToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x929fe9a1" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x94b2294b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa76b3fda" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xabfceffc" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbdcdc258" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc2998238" + }, + { + "constant": true, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc488847b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd02f7351" + }, + { + "constant": false, + "inputs": [ + { + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "_setMaxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd9226ced" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xda3d454c" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdce15449" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCollateralFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe4028eee" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe8755446" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xeabe7d91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xede4edd0" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event", + "signature": "0xcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event", + "signature": "0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event", + "signature": "0xe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event", + "signature": "0x3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event", + "signature": "0x70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event", + "signature": "0xaeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldMaxAssets", + "type": "uint256" + }, + { + "indexed": false, + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "NewMaxAssets", + "type": "event", + "signature": "0x7093cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event", + "signature": "0xd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "cBAT": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "StableCoinInterestRateModel": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event" + }, + { + "constant": true, + "inputs": [ + { + "name": "_asset", + "type": "address" + }, + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + } + ], + "name": "getSupplyRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_asset", + "type": "address" + }, + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ], + "Base0bps_Slope2000bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "cETH": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [], + "name": "mint", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x1249c58b" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": false, + "inputs": [], + "name": "repayBorrow", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x4e4d9fea" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0xaae40a2a" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + } + ], + "name": "repayBorrowBehalf", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0xe5974619" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "Base500bps_Slope1200bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "Base200bps_Slope3000bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "cREP": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "MoneyMarket": [ + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "paused", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationDiscount", + "outputs": [ + { + "name": "mantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "name": "isSupported", + "type": "bool" + }, + { + "name": "blockNumber", + "type": "uint256" + }, + { + "name": "interestRateModel", + "type": "address" + }, + { + "name": "totalSupply", + "type": "uint256" + }, + { + "name": "supplyRateMantissa", + "type": "uint256" + }, + { + "name": "supplyIndex", + "type": "uint256" + }, + { + "name": "totalBorrows", + "type": "uint256" + }, + { + "name": "borrowRateMantissa", + "type": "uint256" + }, + { + "name": "borrowIndex", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "collateralRatio", + "outputs": [ + { + "name": "mantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "address" + } + ], + "name": "supplyBalances", + "outputs": [ + { + "name": "principal", + "type": "uint256" + }, + { + "name": "interestIndex", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "originationFee", + "outputs": [ + { + "name": "mantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "collateralMarkets", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "address" + } + ], + "name": "borrowBalances", + "outputs": [ + { + "name": "principal", + "type": "uint256" + }, + { + "name": "interestIndex", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "account", + "type": "address" + }, + { + "indexed": false, + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "name": "startingBalance", + "type": "uint256" + }, + { + "indexed": false, + "name": "newBalance", + "type": "uint256" + } + ], + "name": "SupplyReceived", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "account", + "type": "address" + }, + { + "indexed": false, + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "name": "startingBalance", + "type": "uint256" + }, + { + "indexed": false, + "name": "newBalance", + "type": "uint256" + } + ], + "name": "SupplyWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "account", + "type": "address" + }, + { + "indexed": false, + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "name": "startingBalance", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowAmountWithFee", + "type": "uint256" + }, + { + "indexed": false, + "name": "newBalance", + "type": "uint256" + } + ], + "name": "BorrowTaken", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "account", + "type": "address" + }, + { + "indexed": false, + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "name": "startingBalance", + "type": "uint256" + }, + { + "indexed": false, + "name": "newBalance", + "type": "uint256" + } + ], + "name": "BorrowRepaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "targetAccount", + "type": "address" + }, + { + "indexed": false, + "name": "assetBorrow", + "type": "address" + }, + { + "indexed": false, + "name": "borrowBalanceBefore", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowBalanceAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "amountRepaid", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowBalanceAfter", + "type": "uint256" + }, + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "assetCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "collateralBalanceBefore", + "type": "uint256" + }, + { + "indexed": false, + "name": "collateralBalanceAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "amountSeized", + "type": "uint256" + }, + { + "indexed": false, + "name": "collateralBalanceAfter", + "type": "uint256" + } + ], + "name": "BorrowLiquidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldOracle", + "type": "address" + }, + { + "indexed": false, + "name": "newOracle", + "type": "address" + } + ], + "name": "NewOracle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "name": "interestRateModel", + "type": "address" + } + ], + "name": "SupportedMarket", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldCollateralRatioMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCollateralRatioMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "oldLiquidationDiscountMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newLiquidationDiscountMantissa", + "type": "uint256" + } + ], + "name": "NewRiskParameters", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldOriginationFeeMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newOriginationFeeMantissa", + "type": "uint256" + } + ], + "name": "NewOriginationFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "name": "interestRateModel", + "type": "address" + } + ], + "name": "SetMarketInterestRateModel", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "asset", + "type": "address" + }, + { + "indexed": false, + "name": "equityAvailableBefore", + "type": "uint256" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "name": "owner", + "type": "address" + } + ], + "name": "EquityWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "asset", + "type": "address" + } + ], + "name": "SuspendedMarket", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "newState", + "type": "bool" + } + ], + "name": "SetPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "getCollateralMarketsLength", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "asset", + "type": "address" + } + ], + "name": "assetPrices", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOracle", + "type": "address" + } + ], + "name": "_setOracle", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "requestedState", + "type": "bool" + } + ], + "name": "_setPaused", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "name": "", + "type": "int256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "asset", + "type": "address" + } + ], + "name": "getSupplyBalance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "asset", + "type": "address" + } + ], + "name": "getBorrowBalance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "asset", + "type": "address" + }, + { + "name": "interestRateModel", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "asset", + "type": "address" + } + ], + "name": "_suspendMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "collateralRatioMantissa", + "type": "uint256" + }, + { + "name": "liquidationDiscountMantissa", + "type": "uint256" + } + ], + "name": "_setRiskParameters", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "originationFeeMantissa", + "type": "uint256" + } + ], + "name": "_setOriginationFee", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "asset", + "type": "address" + }, + { + "name": "interestRateModel", + "type": "address" + } + ], + "name": "_setMarketInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "asset", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "_withdrawEquity", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "asset", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "supply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "asset", + "type": "address" + }, + { + "name": "requestedAmount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "userAddress", + "type": "address" + } + ], + "name": "calculateAccountValues", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "asset", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "targetAccount", + "type": "address" + }, + { + "name": "assetBorrow", + "type": "address" + }, + { + "name": "assetCollateral", + "type": "address" + }, + { + "name": "requestedAmountClose", + "type": "uint256" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "asset", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "cZRX": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "cWBTC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ] +} \ No newline at end of file diff --git a/networks/mainnet.json b/networks/mainnet.json new file mode 100644 index 000000000..e38e96a61 --- /dev/null +++ b/networks/mainnet.json @@ -0,0 +1,269 @@ +{ + "Contracts": { + "ZRX": "0xE41d2489571d322189246DaFA5ebDe1F4699F498", + "cUSDC": "0x39AA39c021dfbaE8faC545936693aC917d5E7563", + "PriceOracle": "0x02557a5e05defeffd4cae6d83ea3d173b272c904", + "PriceOracleProxy": "0x28F829F473638ba82710c8404A778f9a66029aAD", + "Maximillion": "0xf859A1AD94BcF445A406B892eF0d3082f4174088", + "cDAI": "0xF5DCe57282A584D2746FaF1593d3121Fcac444dC", + "DAI": "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359", + "StdComptroller": "0x62F18C451af964197341d3c86D27e98C41BB8fcC", + "Poster": "0x3c6809319201b978d821190ba03fa19a3523bd96", + "Unitroller": "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B", + "Comptroller": "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B", + "cBAT": "0x6C8c6b02E7b2BE14d4fA6022Dfd6d75921D90E4E", + "Base0bps_Slope2000bps": "0xc64C4cBA055eFA614CE01F4BAD8A9F519C4f8FaB", + "BAT": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", + "cETH": "0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5", + "Base500bps_Slope1200bps": "0xa1046abfc2598F48C44Fb320d281d3F3c0733c9a", + "Base200bps_Slope3000bps": "0xBAE04CbF96391086dC643e842b517734E214D698", + "cREP": "0x158079Ee67Fce2f58472A96584A73C7Ab9AC95c1", + "WBTC": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", + "REP": "0x1985365e9f78359a9B6AD760e32412f4a445E862", + "cZRX": "0xB3319f5D18Bc0D84dD1b4825Dcde5d5f7266d407", + "cWBTC": "0xC11b1268C1A384e55C48c2391d8d480264A3A7F4", + "USDC": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + }, + "Blocks": { + "cUSDC": 7710760, + "PriceOracle": 6747538, + "PriceOracleProxy": 7710793, + "Maximillion": 7710775, + "cDAI": 7710752, + "StdComptroller": 7710672, + "Unitroller": 7710671, + "cBAT": 7710735, + "Base0bps_Slope2000bps": 7710727, + "cETH": 7710758, + "Base500bps_Slope1200bps": 7710726, + "Base200bps_Slope3000bps": 7710728, + "cREP": 7710755, + "cZRX": 7710733, + "cWBTC": 8163813 + }, + "Maximillion": { + "description": "Maximillion", + "cEtherAddress": "0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5", + "address": "0xf859A1AD94BcF445A406B892eF0d3082f4174088" + }, + "Unitroller": { + "description": "Unitroller", + "address": "0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B" + }, + "Comptroller": { + "StdComptroller": { + "address": "0x62F18C451af964197341d3c86D27e98C41BB8fcC", + "contract": "Comptroller", + "description": "Standard Comptroller Impl" + } + }, + "Constructors": { + "cUSDC": "0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000003d9819210a31b4961b30ef54be2aed79b9c9cd3b000000000000000000000000c64c4cba055efa614ce01f4bad8a9f519c4f8fab0000000000000000000000000000000000000000000000000000b5e620f4800000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000011436f6d706f756e642055534420436f696e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000056355534443000000000000000000000000000000000000000000000000000000", + "PriceOracleProxy": "0x0000000000000000000000003d9819210a31b4961b30ef54be2aed79b9c9cd3b00000000000000000000000002557a5e05defeffd4cae6d83ea3d173b272c9040000000000000000000000004ddc2d193948926d02f9b1fe9e1daa0718270ed5", + "Maximillion": "0x0000000000000000000000004ddc2d193948926d02f9b1fe9e1daa0718270ed5", + "cDAI": "0x00000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a232603590000000000000000000000003d9819210a31b4961b30ef54be2aed79b9c9cd3b000000000000000000000000a1046abfc2598f48c44fb320d281d3f3c0733c9a000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c436f6d706f756e6420446169000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046344414900000000000000000000000000000000000000000000000000000000", + "StdComptroller": "0x", + "Unitroller": "0x", + "cBAT": "0x0000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef0000000000000000000000003d9819210a31b4961b30ef54be2aed79b9c9cd3b000000000000000000000000bae04cbf96391086dc643e842b517734e214d698000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001e436f6d706f756e6420426173696320417474656e74696f6e20546f6b656e000000000000000000000000000000000000000000000000000000000000000000046342415400000000000000000000000000000000000000000000000000000000", + "Base0bps_Slope2000bps": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c68af0bb140000", + "cETH": "0x0000000000000000000000003d9819210a31b4961b30ef54be2aed79b9c9cd3b000000000000000000000000c64c4cba055efa614ce01f4bad8a9f519c4f8fab000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e436f6d706f756e6420457468657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046345544800000000000000000000000000000000000000000000000000000000", + "Base500bps_Slope1200bps": "0x00000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000001aa535d3d0c0000", + "Base200bps_Slope3000bps": "0x00000000000000000000000000000000000000000000000000470de4df8200000000000000000000000000000000000000000000000000000429d069189e0000", + "cREP": "0x0000000000000000000000001985365e9f78359a9b6ad760e32412f4a445e8620000000000000000000000003d9819210a31b4961b30ef54be2aed79b9c9cd3b000000000000000000000000bae04cbf96391086dc643e842b517734e214d698000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e436f6d706f756e6420417567757200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046352455000000000000000000000000000000000000000000000000000000000", + "cZRX": "0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000003d9819210a31b4961b30ef54be2aed79b9c9cd3b000000000000000000000000bae04cbf96391086dc643e842b517734e214d698000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000b436f6d706f756e642030780000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004635a525800000000000000000000000000000000000000000000000000000000", + "cWBTC": "0x0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c5990000000000000000000000003d9819210a31b4961b30ef54be2aed79b9c9cd3b000000000000000000000000bae04cbf96391086dc643e842b517734e214d69800000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000014436f6d706f756e6420577261707065642042544300000000000000000000000000000000000000000000000000000000000000000000000000000000000000056357425443000000000000000000000000000000000000000000000000000000" + }, + "Tokens": { + "ZRX": { + "name": "0x", + "symbol": "ZRX", + "decimals": 18, + "address": "0xE41d2489571d322189246DaFA5ebDe1F4699F498" + }, + "cUSDC": { + "name": "Compound USD Coin", + "symbol": "cUSDC", + "decimals": 8, + "underlying": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000", + "address": "0x39AA39c021dfbaE8faC545936693aC917d5E7563" + }, + "cDAI": { + "name": "Compound Dai", + "symbol": "cDAI", + "decimals": 8, + "underlying": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xF5DCe57282A584D2746FaF1593d3121Fcac444dC" + }, + "DAI": { + "name": "Dai", + "symbol": "DAI", + "decimals": 18, + "address": "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359", + "reader": "0x729D19f657BD0614b4985Cf1D82531c67569197B" + }, + "cBAT": { + "name": "Compound Basic Attention Token", + "symbol": "cBAT", + "decimals": 8, + "underlying": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x6C8c6b02E7b2BE14d4fA6022Dfd6d75921D90E4E" + }, + "BAT": { + "name": "Basic Attention Token", + "symbol": "BAT", + "decimals": 18, + "address": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF" + }, + "cETH": { + "name": "Compound Ether", + "symbol": "cETH", + "decimals": 8, + "underlying": "", + "contract": "CEther", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5" + }, + "cREP": { + "name": "Compound Augur", + "symbol": "cREP", + "decimals": 8, + "underlying": "0x1985365e9f78359a9B6AD760e32412f4a445E862", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x158079Ee67Fce2f58472A96584A73C7Ab9AC95c1" + }, + "WBTC": { + "name": "Wrapped BTC", + "symbol": "WBTC", + "decimals": 8, + "address": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599" + }, + "REP": { + "name": "Augur", + "symbol": "REP", + "decimals": 18, + "address": "0x1985365e9f78359a9B6AD760e32412f4a445E862" + }, + "cZRX": { + "name": "Compound 0x", + "symbol": "cZRX", + "decimals": 8, + "underlying": "0xE41d2489571d322189246DaFA5ebDe1F4699F498", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xB3319f5D18Bc0D84dD1b4825Dcde5d5f7266d407" + }, + "cWBTC": { + "name": "Compound Wrapped BTC", + "symbol": "cWBTC", + "decimals": 8, + "underlying": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "20000000000000000", + "address": "0xC11b1268C1A384e55C48c2391d8d480264A3A7F4" + }, + "USDC": { + "name": "USD Coin", + "symbol": "USDC", + "decimals": 6, + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + } + }, + "cTokens": { + "cZRX": { + "name": "Compound 0x", + "symbol": "cZRX", + "decimals": 8, + "underlying": "0xE41d2489571d322189246DaFA5ebDe1F4699F498", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xB3319f5D18Bc0D84dD1b4825Dcde5d5f7266d407" + }, + "cBAT": { + "name": "Compound Basic Attention Token", + "symbol": "cBAT", + "decimals": 8, + "underlying": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x6C8c6b02E7b2BE14d4fA6022Dfd6d75921D90E4E" + }, + "cDAI": { + "name": "Compound Dai", + "symbol": "cDAI", + "decimals": 8, + "underlying": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xF5DCe57282A584D2746FaF1593d3121Fcac444dC" + }, + "cREP": { + "name": "Compound Augur", + "symbol": "cREP", + "decimals": 8, + "underlying": "0x1985365e9f78359a9B6AD760e32412f4a445E862", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x158079Ee67Fce2f58472A96584A73C7Ab9AC95c1" + }, + "cETH": { + "name": "Compound Ether", + "symbol": "cETH", + "decimals": 8, + "underlying": "", + "contract": "CEther", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5" + }, + "cUSDC": { + "name": "Compound USD Coin", + "symbol": "cUSDC", + "decimals": 8, + "underlying": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000", + "address": "0x39AA39c021dfbaE8faC545936693aC917d5E7563" + }, + "cWBTC": { + "name": "Compound Wrapped BTC", + "symbol": "cWBTC", + "decimals": 8, + "underlying": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "20000000000000000", + "address": "0xC11b1268C1A384e55C48c2391d8d480264A3A7F4" + } + }, + "InterestRateModel": { + "Base500bps_Slope1200bps": { + "name": "Base500bps_Slope1200bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=50000000000000000 multiplier=120000000000000000", + "base": "50000000000000000", + "slope": "120000000000000000", + "address": "0xa1046abfc2598F48C44Fb320d281d3F3c0733c9a" + }, + "Base0bps_Slope2000bps": { + "name": "Base0bps_Slope2000bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=0 multiplier=200000000000000000", + "base": "0", + "slope": "200000000000000000", + "address": "0xc64C4cBA055eFA614CE01F4BAD8A9F519C4f8FaB" + }, + "Base200bps_Slope3000bps": { + "name": "Base200bps_Slope3000bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=20000000000000000 multiplier=300000000000000000", + "base": "20000000000000000", + "slope": "300000000000000000", + "address": "0xBAE04CbF96391086dC643e842b517734E214D698" + } + } +} \ No newline at end of file diff --git a/networks/rinkeby-abi.json b/networks/rinkeby-abi.json new file mode 100644 index 000000000..550d04c42 --- /dev/null +++ b/networks/rinkeby-abi.json @@ -0,0 +1,15614 @@ +{ + "ZRX": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + } + ], + "cUSDC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "StableInterest": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "PriceOracle": [ + { + "constant": true, + "inputs": [], + "name": "isPriceOracle", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function", + "signature": "0x66331bba" + }, + { + "constant": true, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "getUnderlyingPrice", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfc57d4df" + } + ], + "StandardInterest": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "ZeroComptroller": [ + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x007e3dd2" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x1ededc91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x24008a62" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x317b0b77" + }, + { + "constant": false, + "inputs": [ + { + "name": "unitroller", + "type": "address" + }, + { + "name": "_oracle", + "type": "address" + }, + { + "name": "_closeFactorMantissa", + "type": "uint256" + }, + { + "name": "_maxAssets", + "type": "uint256" + }, + { + "name": "reinitializing", + "type": "bool" + } + ], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x32000e00" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + }, + { + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x41c728b9" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x47ef3b3b" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x4ada90af" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4ef4c3e1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "_setLiquidationIncentive", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4fd42e17" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemAmount", + "type": "uint256" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x51dff989" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x55ee1fe1" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5c778605" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5ec88c79" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5fc7e71e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6a56947e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6d35bf91" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x7dc0d1d0" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "name": "isListed", + "type": "bool" + }, + { + "name": "collateralFactorMantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8e8f294b" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "cToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x929fe9a1" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x94b2294b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa76b3fda" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xabfceffc" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbdcdc258" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc2998238" + }, + { + "constant": true, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc488847b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd02f7351" + }, + { + "constant": false, + "inputs": [ + { + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "_setMaxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd9226ced" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xda3d454c" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdce15449" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCollateralFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe4028eee" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe8755446" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xeabe7d91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xede4edd0" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event", + "signature": "0xcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event", + "signature": "0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event", + "signature": "0xe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event", + "signature": "0x3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event", + "signature": "0x70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event", + "signature": "0xaeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldMaxAssets", + "type": "uint256" + }, + { + "indexed": false, + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "NewMaxAssets", + "type": "event", + "signature": "0x7093cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event", + "signature": "0xd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "PriceOracleProxy": [ + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": true, + "inputs": [], + "name": "isPriceOracle", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x66331bba" + }, + { + "constant": true, + "inputs": [], + "name": "cEtherAddress", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xde836acf" + }, + { + "constant": true, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "getUnderlyingPrice", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfc57d4df" + }, + { + "constant": true, + "inputs": [], + "name": "v1PriceOracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe10c98d" + }, + { + "inputs": [ + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "v1PriceOracle_", + "type": "address" + }, + { + "name": "cEtherAddress_", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "Maximillion": [ + { + "constant": true, + "inputs": [], + "name": "cEther", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x19b68c00" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "cEther_", + "type": "address" + } + ], + "name": "repayBehalfExplicit", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x367b7f05" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + } + ], + "name": "repayBehalf", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x9f35c3d5" + }, + { + "inputs": [ + { + "name": "cEther_", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "cDAI": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "DAI": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + } + ], + "StdComptroller": [ + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x007e3dd2" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x1ededc91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x24008a62" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x317b0b77" + }, + { + "constant": false, + "inputs": [ + { + "name": "unitroller", + "type": "address" + }, + { + "name": "_oracle", + "type": "address" + }, + { + "name": "_closeFactorMantissa", + "type": "uint256" + }, + { + "name": "_maxAssets", + "type": "uint256" + }, + { + "name": "reinitializing", + "type": "bool" + } + ], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x32000e00" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + }, + { + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x41c728b9" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x47ef3b3b" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x4ada90af" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4ef4c3e1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "_setLiquidationIncentive", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4fd42e17" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemAmount", + "type": "uint256" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x51dff989" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x55ee1fe1" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5c778605" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5ec88c79" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5fc7e71e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6a56947e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6d35bf91" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x7dc0d1d0" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "name": "isListed", + "type": "bool" + }, + { + "name": "collateralFactorMantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8e8f294b" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "cToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x929fe9a1" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x94b2294b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa76b3fda" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xabfceffc" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbdcdc258" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc2998238" + }, + { + "constant": true, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc488847b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd02f7351" + }, + { + "constant": false, + "inputs": [ + { + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "_setMaxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd9226ced" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xda3d454c" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdce15449" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCollateralFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe4028eee" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe8755446" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xeabe7d91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xede4edd0" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event", + "signature": "0xcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event", + "signature": "0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event", + "signature": "0xe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event", + "signature": "0x3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event", + "signature": "0x70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event", + "signature": "0xaeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldMaxAssets", + "type": "uint256" + }, + { + "indexed": false, + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "NewMaxAssets", + "type": "event", + "signature": "0x7093cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event", + "signature": "0xd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "Unitroller": [ + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc1e80334" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "_setPendingImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe992a041" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "NewPendingImplementation", + "type": "event", + "signature": "0xe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d815" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newImplementation", + "type": "address" + } + ], + "name": "NewImplementation", + "type": "event", + "signature": "0xd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "Comptroller": [ + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc1e80334" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "_setPendingImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe992a041" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "NewPendingImplementation", + "type": "event", + "signature": "0xe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d815" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newImplementation", + "type": "address" + } + ], + "name": "NewImplementation", + "type": "event", + "signature": "0xd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x007e3dd2" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x1ededc91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x24008a62" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x317b0b77" + }, + { + "constant": false, + "inputs": [ + { + "name": "unitroller", + "type": "address" + }, + { + "name": "_oracle", + "type": "address" + }, + { + "name": "_closeFactorMantissa", + "type": "uint256" + }, + { + "name": "_maxAssets", + "type": "uint256" + }, + { + "name": "reinitializing", + "type": "bool" + } + ], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x32000e00" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + }, + { + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x41c728b9" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x47ef3b3b" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x4ada90af" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4ef4c3e1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "_setLiquidationIncentive", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4fd42e17" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemAmount", + "type": "uint256" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x51dff989" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x55ee1fe1" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5c778605" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5ec88c79" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5fc7e71e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6a56947e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6d35bf91" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x7dc0d1d0" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "name": "isListed", + "type": "bool" + }, + { + "name": "collateralFactorMantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8e8f294b" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "cToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x929fe9a1" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x94b2294b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa76b3fda" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xabfceffc" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbdcdc258" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc2998238" + }, + { + "constant": true, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc488847b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd02f7351" + }, + { + "constant": false, + "inputs": [ + { + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "_setMaxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd9226ced" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xda3d454c" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdce15449" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCollateralFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe4028eee" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe8755446" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xeabe7d91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xede4edd0" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event", + "signature": "0xcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event", + "signature": "0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event", + "signature": "0xe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event", + "signature": "0x3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event", + "signature": "0x70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event", + "signature": "0xaeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldMaxAssets", + "type": "uint256" + }, + { + "indexed": false, + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "NewMaxAssets", + "type": "event", + "signature": "0x7093cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event", + "signature": "0xd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x007e3dd2" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x1ededc91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x24008a62" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x317b0b77" + }, + { + "constant": false, + "inputs": [ + { + "name": "unitroller", + "type": "address" + }, + { + "name": "_oracle", + "type": "address" + }, + { + "name": "_closeFactorMantissa", + "type": "uint256" + }, + { + "name": "_maxAssets", + "type": "uint256" + }, + { + "name": "reinitializing", + "type": "bool" + } + ], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x32000e00" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + }, + { + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x41c728b9" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x47ef3b3b" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x4ada90af" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4ef4c3e1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "_setLiquidationIncentive", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4fd42e17" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemAmount", + "type": "uint256" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x51dff989" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x55ee1fe1" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5c778605" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5ec88c79" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5fc7e71e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6a56947e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6d35bf91" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x7dc0d1d0" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "name": "isListed", + "type": "bool" + }, + { + "name": "collateralFactorMantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8e8f294b" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "cToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x929fe9a1" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x94b2294b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa76b3fda" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xabfceffc" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbdcdc258" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc2998238" + }, + { + "constant": true, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc488847b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd02f7351" + }, + { + "constant": false, + "inputs": [ + { + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "_setMaxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd9226ced" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xda3d454c" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdce15449" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCollateralFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe4028eee" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe8755446" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xeabe7d91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xede4edd0" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event", + "signature": "0xcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event", + "signature": "0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event", + "signature": "0xe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event", + "signature": "0x3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event", + "signature": "0x70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event", + "signature": "0xaeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldMaxAssets", + "type": "uint256" + }, + { + "indexed": false, + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "NewMaxAssets", + "type": "event", + "signature": "0x7093cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event", + "signature": "0xd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "cBAT": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "Base0bps_Slope2000bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "BAT": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + } + ], + "cETH": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [], + "name": "mint", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x1249c58b" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": false, + "inputs": [], + "name": "repayBorrow", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x4e4d9fea" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0xaae40a2a" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + } + ], + "name": "repayBorrowBehalf", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0xe5974619" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "Base500bps_Slope1200bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "Base200bps_Slope3000bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "cREP": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "REP": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + } + ], + "cZRX": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "USDC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + } + ], + "cWBTC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ] +} \ No newline at end of file diff --git a/networks/rinkeby.json b/networks/rinkeby.json new file mode 100644 index 000000000..c8349eae5 --- /dev/null +++ b/networks/rinkeby.json @@ -0,0 +1,291 @@ +{ + "Contracts": { + "ZRX": "0xddea378A6dDC8AfeC82C36E9b0078826bf9e68B6", + "cUSDC": "0x5B281A6DdA0B271e91ae35DE655Ad301C976edb1", + "PriceOracle": "0xD2B1eCa822550d9358e97e72c6C1a93AE28408d0", + "ZeroComptroller": "0x16e175eE9f555E43FD01f3aFa359A37b10e5139b", + "PriceOracleProxy": "0x332B6e69f21ACdBA5fb3e8DaC56ff81878527E06", + "Maximillion": "0xFBBDBa59516adA2eADf50f96cE0151edC9e0A674", + "cDAI": "0x6D7F0754FFeb405d23C51CE938289d4835bE3b14", + "DAI": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa", + "StdComptroller": "0x99127FD9840Cbc2bBfF43dF443887f4d96268916", + "Unitroller": "0x2EAa9D77AE4D8f9cdD9FAAcd44016E746485bddb", + "Comptroller": "0x2EAa9D77AE4D8f9cdD9FAAcd44016E746485bddb", + "cBAT": "0xEBf1A11532b93a529b5bC942B4bAA98647913002", + "Base0bps_Slope2000bps": "0x1A43BFd39B15DcF444e17Ab408C4b5be32DEB7F5", + "BAT": "0xbF7A7169562078c96f0eC1A8aFD6aE50f12e5A99", + "cETH": "0xd6801a1DfFCd0a410336Ef88DeF4320D6DF1883e", + "Base500bps_Slope1200bps": "0xE12630c8Fdd7d0096c9Cd72Cd228598AEBe58795", + "Base200bps_Slope3000bps": "0x6330D442A2D7eE4DC66C0adb9969e8702aEfc9fE", + "cREP": "0xEBe09eB3411D18F4FF8D859e096C533CAC5c6B60", + "WBTC": "0x577D296678535e4903D59A4C929B718e1D575e0A", + "REP": "0x6e894660985207feb7cf89Faf048998c71E8EE89", + "cZRX": "0x52201ff1720134bBbBB2f6BC97Bf3715490EC19B", + "cWBTC": "0x0014F450B8Ae7708593F4A46F8fa6E5D50620F96", + "USDC": "0x4DBCdF9B62e891a7cec5A2568C3F4FAF9E8Abe2b" + }, + "Blocks": { + "cUSDC": 4319847, + "ZeroComptroller": 4347719, + "PriceOracleProxy": 4319855, + "Maximillion": 4319848, + "cDAI": 4319844, + "StdComptroller": 4319836, + "Unitroller": 4319835, + "cBAT": 4319843, + "Base0bps_Slope2000bps": 4319840, + "cETH": 4319846, + "Base500bps_Slope1200bps": 4319839, + "Base200bps_Slope3000bps": 4319841, + "cREP": 4319845, + "WBTC": 4717533, + "cZRX": 4319842, + "cWBTC": 4717535 + }, + "PriceOracleProxy": { + "description": "Price Oracle Proxy", + "cEther": "0xd6801a1DfFCd0a410336Ef88DeF4320D6DF1883e", + "cUSDC": "0x5B281A6DdA0B271e91ae35DE655Ad301C976edb1", + "address": "0xee1E6a73937757fdBf9d23F857f7788b282386c6" + }, + "Maximillion": { + "description": "Maximillion", + "cEtherAddress": "0xd6801a1DfFCd0a410336Ef88DeF4320D6DF1883e", + "address": "0xFBBDBa59516adA2eADf50f96cE0151edC9e0A674" + }, + "Unitroller": { + "description": "Unitroller", + "address": "0x2EAa9D77AE4D8f9cdD9FAAcd44016E746485bddb" + }, + "Comptroller": { + "StdComptroller": { + "address": "0x99127FD9840Cbc2bBfF43dF443887f4d96268916", + "contract": "Comptroller", + "description": "Standard Comptroller Impl" + }, + "ZeroComptroller": { + "address": "0x16e175eE9f555E43FD01f3aFa359A37b10e5139b", + "contract": "Comptroller", + "description": "Standard Comptroller Impl" + } + }, + "Constructors": { + "ZRX": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000002307800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a52580000000000000000000000000000000000000000000000000000000000", + "cUSDC": "0x0000000000000000000000004dbcdf9b62e891a7cec5a2568c3f4faf9e8abe2b0000000000000000000000002eaa9d77ae4d8f9cdd9faacd44016e746485bddb0000000000000000000000001a43bfd39b15dcf444e17ab408c4b5be32deb7f50000000000000000000000000000000000000000000000000000b5e620f4800000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000016436f6d706f756e642055534420436f696e20f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000000000056355534443000000000000000000000000000000000000000000000000000000", + "ZeroComptroller": "0x", + "PriceOracleProxy": "0x0000000000000000000000002eaa9d77ae4d8f9cdd9faacd44016e746485bddb000000000000000000000000d2b1eca822550d9358e97e72c6c1a93ae28408d0000000000000000000000000d6801a1dffcd0a410336ef88def4320d6df1883e", + "Maximillion": "0x000000000000000000000000d6801a1dffcd0a410336ef88def4320d6df1883e", + "cDAI": "0x0000000000000000000000005592ec0cfb4dbc12d3ab100b257153436a1f0fea0000000000000000000000002eaa9d77ae4d8f9cdd9faacd44016e746485bddb000000000000000000000000e12630c8fdd7d0096c9cd72cd228598aebe58795000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000011436f6d706f756e642044616920f09f938800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046344414900000000000000000000000000000000000000000000000000000000", + "DAI": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000003446169000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034441490000000000000000000000000000000000000000000000000000000000", + "StdComptroller": "0x", + "Unitroller": "0x", + "cBAT": "0x000000000000000000000000bf7a7169562078c96f0ec1a8afd6ae50f12e5a990000000000000000000000002eaa9d77ae4d8f9cdd9faacd44016e746485bddb0000000000000000000000006330d442a2d7ee4dc66c0adb9969e8702aefc9fe000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000023436f6d706f756e6420426173696320417474656e74696f6e20546f6b656e20f09f9388000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046342415400000000000000000000000000000000000000000000000000000000", + "Base0bps_Slope2000bps": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c68af0bb140000", + "BAT": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000015426173696320417474656e74696f6e20546f6b656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000034241540000000000000000000000000000000000000000000000000000000000", + "cETH": "0x0000000000000000000000002eaa9d77ae4d8f9cdd9faacd44016e746485bddb0000000000000000000000001a43bfd39b15dcf444e17ab408c4b5be32deb7f5000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000013436f6d706f756e6420457468657220f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046345544800000000000000000000000000000000000000000000000000000000", + "Base500bps_Slope1200bps": "0x00000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000001aa535d3d0c0000", + "Base200bps_Slope3000bps": "0x00000000000000000000000000000000000000000000000000470de4df8200000000000000000000000000000000000000000000000000000429d069189e0000", + "cREP": "0x0000000000000000000000006e894660985207feb7cf89faf048998c71e8ee890000000000000000000000002eaa9d77ae4d8f9cdd9faacd44016e746485bddb0000000000000000000000006330d442a2d7ee4dc66c0adb9969e8702aefc9fe000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000013436f6d706f756e6420417567757220f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046352455000000000000000000000000000000000000000000000000000000000", + "WBTC": "0x", + "REP": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000005417567757200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035245500000000000000000000000000000000000000000000000000000000000", + "cZRX": "0x000000000000000000000000ddea378a6ddc8afec82c36e9b0078826bf9e68b60000000000000000000000002eaa9d77ae4d8f9cdd9faacd44016e746485bddb0000000000000000000000006330d442a2d7ee4dc66c0adb9969e8702aefc9fe000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010436f6d706f756e6420307820f09f9388000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004635a525800000000000000000000000000000000000000000000000000000000", + "cWBTC": "0x000000000000000000000000577d296678535e4903d59a4c929b718e1d575e0a0000000000000000000000002eaa9d77ae4d8f9cdd9faacd44016e746485bddb0000000000000000000000006330d442a2d7ee4dc66c0adb9969e8702aefc9fe00000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000019436f6d706f756e6420577261707065642042544320f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000056357425443000000000000000000000000000000000000000000000000000000", + "USDC": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000855534420436f696e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045553444300000000000000000000000000000000000000000000000000000000" + }, + "Tokens": { + "ZRX": { + "name": "0x", + "symbol": "ZRX", + "decimals": 18, + "address": "0xddea378A6dDC8AfeC82C36E9b0078826bf9e68B6" + }, + "cUSDC": { + "name": "Compound USD Coin 📈", + "symbol": "cUSDC", + "decimals": 8, + "underlying": "0x4DBCdF9B62e891a7cec5A2568C3F4FAF9E8Abe2b", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000", + "address": "0x5B281A6DdA0B271e91ae35DE655Ad301C976edb1" + }, + "cDAI": { + "name": "Compound Dai 📈", + "symbol": "cDAI", + "decimals": 8, + "underlying": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x6D7F0754FFeb405d23C51CE938289d4835bE3b14" + }, + "DAI": { + "name": "Dai", + "symbol": "DAI", + "decimals": 18, + "address": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa" + }, + "cBAT": { + "name": "Compound Basic Attention Token 📈", + "symbol": "cBAT", + "decimals": 8, + "underlying": "0xbF7A7169562078c96f0eC1A8aFD6aE50f12e5A99", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xEBf1A11532b93a529b5bC942B4bAA98647913002" + }, + "BAT": { + "name": "Basic Attention Token", + "symbol": "BAT", + "decimals": 18, + "address": "0xbF7A7169562078c96f0eC1A8aFD6aE50f12e5A99" + }, + "cETH": { + "name": "Compound Ether 📈", + "symbol": "cETH", + "decimals": 8, + "underlying": "", + "contract": "CEther", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xd6801a1DfFCd0a410336Ef88DeF4320D6DF1883e" + }, + "cREP": { + "name": "Compound Augur 📈", + "symbol": "cREP", + "decimals": 8, + "underlying": "0x6e894660985207feb7cf89Faf048998c71E8EE89", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xEBe09eB3411D18F4FF8D859e096C533CAC5c6B60" + }, + "WBTC": { + "description": "WBTC", + "name": "Wrapped BTC", + "symbol": "WBTC", + "decimals": 8, + "contract": "WBTCToken", + "address": "0x577D296678535e4903D59A4C929B718e1D575e0A" + }, + "REP": { + "name": "Augur", + "symbol": "REP", + "decimals": 18, + "address": "0x6e894660985207feb7cf89Faf048998c71E8EE89" + }, + "cZRX": { + "name": "Compound 0x 📈", + "symbol": "cZRX", + "decimals": 8, + "underlying": "0xddea378A6dDC8AfeC82C36E9b0078826bf9e68B6", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x52201ff1720134bBbBB2f6BC97Bf3715490EC19B" + }, + "cWBTC": { + "name": "Compound Wrapped BTC 📈", + "symbol": "cWBTC", + "decimals": 8, + "underlying": "0x577D296678535e4903D59A4C929B718e1D575e0A", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "20000000000000000", + "address": "0x0014F450B8Ae7708593F4A46F8fa6E5D50620F96" + }, + "USDC": { + "description": "Standard", + "name": "USD Coin", + "symbol": "USDC", + "decimals": 6, + "address": "0x4DBCdF9B62e891a7cec5A2568C3F4FAF9E8Abe2b", + "contract": "FaucetToken" + } + }, + "cTokens": { + "cZRX": { + "name": "Compound 0x 📈", + "symbol": "cZRX", + "decimals": 8, + "underlying": "0xddea378A6dDC8AfeC82C36E9b0078826bf9e68B6", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x52201ff1720134bBbBB2f6BC97Bf3715490EC19B" + }, + "cBAT": { + "name": "Compound Basic Attention Token 📈", + "symbol": "cBAT", + "decimals": 8, + "underlying": "0xbF7A7169562078c96f0eC1A8aFD6aE50f12e5A99", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xEBf1A11532b93a529b5bC942B4bAA98647913002" + }, + "cDAI": { + "name": "Compound Dai 📈", + "symbol": "cDAI", + "decimals": 8, + "underlying": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x6D7F0754FFeb405d23C51CE938289d4835bE3b14" + }, + "cREP": { + "name": "Compound Augur 📈", + "symbol": "cREP", + "decimals": 8, + "underlying": "0x6e894660985207feb7cf89Faf048998c71E8EE89", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xEBe09eB3411D18F4FF8D859e096C533CAC5c6B60" + }, + "cETH": { + "name": "Compound Ether 📈", + "symbol": "cETH", + "decimals": 8, + "underlying": "", + "contract": "CEther", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xd6801a1DfFCd0a410336Ef88DeF4320D6DF1883e" + }, + "cUSDC": { + "name": "Compound USD Coin 📈", + "symbol": "cUSDC", + "decimals": 8, + "underlying": "0x4DBCdF9B62e891a7cec5A2568C3F4FAF9E8Abe2b", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000", + "address": "0x5B281A6DdA0B271e91ae35DE655Ad301C976edb1" + }, + "cWBTC": { + "name": "Compound Wrapped BTC 📈", + "symbol": "cWBTC", + "decimals": 8, + "underlying": "0x577D296678535e4903D59A4C929B718e1D575e0A", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "20000000000000000", + "address": "0x0014F450B8Ae7708593F4A46F8fa6E5D50620F96" + } + }, + "InterestRateModel": { + "Base500bps_Slope1200bps": { + "name": "Base500bps_Slope1200bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=50000000000000000 multiplier=120000000000000000", + "base": "50000000000000000", + "slope": "120000000000000000", + "address": "0xE12630c8Fdd7d0096c9Cd72Cd228598AEBe58795" + }, + "Base0bps_Slope2000bps": { + "name": "Base0bps_Slope2000bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=0 multiplier=200000000000000000", + "base": "0", + "slope": "200000000000000000", + "address": "0x1A43BFd39B15DcF444e17Ab408C4b5be32DEB7F5" + }, + "Base200bps_Slope3000bps": { + "name": "Base200bps_Slope3000bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=20000000000000000 multiplier=300000000000000000", + "base": "20000000000000000", + "slope": "300000000000000000", + "address": "0x6330D442A2D7eE4DC66C0adb9969e8702aEfc9fE" + } + } +} \ No newline at end of file diff --git a/networks/ropsten-abi.json b/networks/ropsten-abi.json new file mode 100644 index 000000000..1694872a4 --- /dev/null +++ b/networks/ropsten-abi.json @@ -0,0 +1,13952 @@ +{ + "ZRX": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "cUSDC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "PriceOracle": [ + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "underlyingPriceMantissa", + "type": "uint256" + } + ], + "name": "setUnderlyingPrice", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x127ffda0" + }, + { + "constant": true, + "inputs": [ + { + "name": "asset", + "type": "address" + } + ], + "name": "assetPrices", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5e9a523c" + }, + { + "constant": true, + "inputs": [], + "name": "isPriceOracle", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x66331bba" + }, + { + "constant": true, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "getUnderlyingPrice", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfc57d4df" + } + ], + "PriceOracleProxy": [ + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": true, + "inputs": [], + "name": "isPriceOracle", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x66331bba" + }, + { + "constant": true, + "inputs": [], + "name": "cEtherAddress", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xde836acf" + }, + { + "constant": true, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "getUnderlyingPrice", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfc57d4df" + }, + { + "constant": true, + "inputs": [], + "name": "v1PriceOracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe10c98d" + }, + { + "inputs": [ + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "v1PriceOracle_", + "type": "address" + }, + { + "name": "cEtherAddress_", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "Maximillion": [ + { + "constant": true, + "inputs": [], + "name": "cEther", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x19b68c00" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "cEther_", + "type": "address" + } + ], + "name": "repayBehalfExplicit", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x367b7f05" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + } + ], + "name": "repayBehalf", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x9f35c3d5" + }, + { + "inputs": [ + { + "name": "cEther_", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "cDAI": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "DAI": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "StdComptroller": [ + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x007e3dd2" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x1ededc91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x24008a62" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x317b0b77" + }, + { + "constant": false, + "inputs": [ + { + "name": "unitroller", + "type": "address" + }, + { + "name": "_oracle", + "type": "address" + }, + { + "name": "_closeFactorMantissa", + "type": "uint256" + }, + { + "name": "_maxAssets", + "type": "uint256" + }, + { + "name": "reinitializing", + "type": "bool" + } + ], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x32000e00" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + }, + { + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x41c728b9" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x47ef3b3b" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x4ada90af" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4ef4c3e1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "_setLiquidationIncentive", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4fd42e17" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemAmount", + "type": "uint256" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x51dff989" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x55ee1fe1" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5c778605" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5ec88c79" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5fc7e71e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6a56947e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6d35bf91" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x7dc0d1d0" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "name": "isListed", + "type": "bool" + }, + { + "name": "collateralFactorMantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8e8f294b" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "cToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x929fe9a1" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x94b2294b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa76b3fda" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xabfceffc" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbdcdc258" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc2998238" + }, + { + "constant": true, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc488847b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd02f7351" + }, + { + "constant": false, + "inputs": [ + { + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "_setMaxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd9226ced" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xda3d454c" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdce15449" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCollateralFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe4028eee" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe8755446" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xeabe7d91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xede4edd0" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event", + "signature": "0xcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event", + "signature": "0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event", + "signature": "0xe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event", + "signature": "0x3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event", + "signature": "0x70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event", + "signature": "0xaeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldMaxAssets", + "type": "uint256" + }, + { + "indexed": false, + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "NewMaxAssets", + "type": "event", + "signature": "0x7093cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event", + "signature": "0xd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "Unitroller": [ + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc1e80334" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "_setPendingImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe992a041" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "NewPendingImplementation", + "type": "event", + "signature": "0xe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d815" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newImplementation", + "type": "address" + } + ], + "name": "NewImplementation", + "type": "event", + "signature": "0xd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "Comptroller": [ + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc1e80334" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "_setPendingImplementation", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe992a041" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingImplementation", + "type": "address" + } + ], + "name": "NewPendingImplementation", + "type": "event", + "signature": "0xe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d815" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldImplementation", + "type": "address" + }, + { + "indexed": false, + "name": "newImplementation", + "type": "address" + } + ], + "name": "NewImplementation", + "type": "event", + "signature": "0xd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x007e3dd2" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "borrowerIndex", + "type": "uint256" + } + ], + "name": "repayBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x1ededc91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "payer", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x24008a62" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": false, + "inputs": [ + { + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCloseFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x317b0b77" + }, + { + "constant": false, + "inputs": [ + { + "name": "unitroller", + "type": "address" + }, + { + "name": "_oracle", + "type": "address" + }, + { + "name": "_closeFactorMantissa", + "type": "uint256" + }, + { + "name": "_maxAssets", + "type": "uint256" + }, + { + "name": "reinitializing", + "type": "bool" + } + ], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x32000e00" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + }, + { + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "mintVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x41c728b9" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x47ef3b3b" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x4ada90af" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "minter", + "type": "address" + }, + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mintAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4ef4c3e1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "_setLiquidationIncentive", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4fd42e17" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemAmount", + "type": "uint256" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x51dff989" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOracle", + "type": "address" + } + ], + "name": "_setPriceOracle", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x55ee1fe1" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5c778605" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountLiquidity", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5ec88c79" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateBorrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x5fc7e71e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6a56947e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x6d35bf91" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x7dc0d1d0" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "markets", + "outputs": [ + { + "name": "isListed", + "type": "bool" + }, + { + "name": "collateralFactorMantissa", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8e8f294b" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + }, + { + "name": "cToken", + "type": "address" + } + ], + "name": "checkMembership", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x929fe9a1" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x94b2294b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + } + ], + "name": "_supportMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa76b3fda" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAssetsIn", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xabfceffc" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xbb82aa5e" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "transferTokens", + "type": "uint256" + } + ], + "name": "transferAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbdcdc258" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokens", + "type": "address[]" + } + ], + "name": "enterMarkets", + "outputs": [ + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc2998238" + }, + { + "constant": true, + "inputs": [ + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc488847b" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenCollateral", + "type": "address" + }, + { + "name": "cTokenBorrowed", + "type": "address" + }, + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seizeAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd02f7351" + }, + { + "constant": false, + "inputs": [ + { + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "_setMaxAssets", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd9226ced" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrowAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xda3d454c" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "name": "accountAssets", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdce15449" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdcfbc0c7" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "_setCollateralFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe4028eee" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe8755446" + }, + { + "constant": false, + "inputs": [ + { + "name": "cToken", + "type": "address" + }, + { + "name": "redeemer", + "type": "address" + }, + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeemAllowed", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xeabe7d91" + }, + { + "constant": false, + "inputs": [ + { + "name": "cTokenAddress", + "type": "address" + } + ], + "name": "exitMarket", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xede4edd0" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + } + ], + "name": "MarketListed", + "type": "event", + "signature": "0xcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketEntered", + "type": "event", + "signature": "0x3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "account", + "type": "address" + } + ], + "name": "MarketExited", + "type": "event", + "signature": "0xe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldCloseFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCloseFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCloseFactor", + "type": "event", + "signature": "0x3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "cToken", + "type": "address" + }, + { + "indexed": false, + "name": "oldCollateralFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newCollateralFactorMantissa", + "type": "uint256" + } + ], + "name": "NewCollateralFactor", + "type": "event", + "signature": "0x70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldLiquidationIncentiveMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newLiquidationIncentiveMantissa", + "type": "uint256" + } + ], + "name": "NewLiquidationIncentive", + "type": "event", + "signature": "0xaeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldMaxAssets", + "type": "uint256" + }, + { + "indexed": false, + "name": "newMaxAssets", + "type": "uint256" + } + ], + "name": "NewMaxAssets", + "type": "event", + "signature": "0x7093cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPriceOracle", + "type": "address" + }, + { + "indexed": false, + "name": "newPriceOracle", + "type": "address" + } + ], + "name": "NewPriceOracle", + "type": "event", + "signature": "0xd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + } + ], + "cBAT": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "Base0bps_Slope2000bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "BAT": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "cETH": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [], + "name": "mint", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x1249c58b" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": false, + "inputs": [], + "name": "repayBorrow", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0x4e4d9fea" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0xaae40a2a" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + } + ], + "name": "repayBorrowBehalf", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function", + "signature": "0xe5974619" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "Base500bps_Slope1200bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "Base200bps_Slope3000bps": [ + { + "constant": true, + "inputs": [ + { + "name": "cash", + "type": "uint256" + }, + { + "name": "borrows", + "type": "uint256" + }, + { + "name": "_reserves", + "type": "uint256" + } + ], + "name": "getBorrowRate", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x15f24053" + }, + { + "constant": true, + "inputs": [], + "name": "multiplier", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1b3ed722" + }, + { + "constant": true, + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x1f68f20a" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x2191f92a" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xa385fb96" + }, + { + "inputs": [ + { + "name": "baseRate_", + "type": "uint256" + }, + { + "name": "multiplier_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + } + ], + "cREP": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "WBTC": [ + { + "constant": true, + "inputs": [], + "name": "mintingFinished", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x05d2035b" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + } + ], + "name": "reclaimToken", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17ffc320" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [], + "name": "unpause", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3f4ba83a" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x40c10f19" + }, + { + "constant": false, + "inputs": [ + { + "name": "value", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x42966c68" + }, + { + "constant": false, + "inputs": [], + "name": "claimOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4e71e0c8" + }, + { + "constant": true, + "inputs": [], + "name": "paused", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5c975abb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x715018a6" + }, + { + "constant": false, + "inputs": [], + "name": "finishMinting", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x7d64bcb4" + }, + { + "constant": false, + "inputs": [], + "name": "pause", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x8456cb59" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8da5cb5b" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "success", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": true, + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xe30c3978" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2fde38b" + }, + { + "anonymous": false, + "inputs": [], + "name": "Pause", + "type": "event", + "signature": "0x6985a02210a168e66602d3235cb6db0e70f92b3ba4d376a33c0f3d9434bff625" + }, + { + "anonymous": false, + "inputs": [], + "name": "Unpause", + "type": "event", + "signature": "0x7805862f689e2f13df9f062ff482ad3ad112aca9e0847911ed832e158c525b33" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "burner", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Burn", + "type": "event", + "signature": "0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885" + }, + { + "anonymous": false, + "inputs": [], + "name": "MintFinished", + "type": "event", + "signature": "0xae5184fba832cb2b1f702aca6117b8d265eaf03ad33eb133f19dde0f5920fa08" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "previousOwner", + "type": "address" + } + ], + "name": "OwnershipRenounced", + "type": "event", + "signature": "0xf8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c64820" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event", + "signature": "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "REP": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ], + "cZRX": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "cWBTC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "spender", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": false, + "inputs": [ + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x0e752702" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x173b9904" + }, + { + "constant": false, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x17bfdfbc" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x182df0f5" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + } + ], + "name": "repayBorrowBehalf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x2608f818" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x26782247" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOfUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x3af9e669" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x3b1d21a2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newComptroller", + "type": "address" + } + ], + "name": "_setComptroller", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x4576b5db" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x47bd3718" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x5fe3b567" + }, + { + "constant": false, + "inputs": [ + { + "name": "reduceAmount", + "type": "uint256" + } + ], + "name": "_reduceReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x601a0bf1" + }, + { + "constant": true, + "inputs": [], + "name": "initialExchangeRateMantissa", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x675d972c" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6c540baf" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x6f307dc3" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x73acee98" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemAmount", + "type": "uint256" + } + ], + "name": "redeemUnderlying", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x852a12e3" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x8f840ddd" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "borrowBalanceStored", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95dd9193" + }, + { + "constant": false, + "inputs": [ + { + "name": "mintAmount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa0712d68" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa6afed95" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xaa5af0fd" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xae9d70b0" + }, + { + "constant": false, + "inputs": [ + { + "name": "liquidator", + "type": "address" + }, + { + "name": "borrower", + "type": "address" + }, + { + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "seize", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb2a02ff1" + }, + { + "constant": false, + "inputs": [ + { + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "_setPendingAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xb71d1a0c" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xbd6d894d" + }, + { + "constant": true, + "inputs": [ + { + "name": "account", + "type": "address" + } + ], + "name": "getAccountSnapshot", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xc37f68e2" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrowAmount", + "type": "uint256" + } + ], + "name": "borrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xc5ebeaec" + }, + { + "constant": false, + "inputs": [ + { + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "redeem", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xdb006a75" + }, + { + "constant": true, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xe9c714f2" + }, + { + "constant": false, + "inputs": [ + { + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "_setInterestRateModel", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf2b3abbd" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf3fdb15a" + }, + { + "constant": false, + "inputs": [ + { + "name": "borrower", + "type": "address" + }, + { + "name": "repayAmount", + "type": "uint256" + }, + { + "name": "cTokenCollateral", + "type": "address" + } + ], + "name": "liquidateBorrow", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xf5e3c462" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf851a440" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xf8f9da28" + }, + { + "constant": false, + "inputs": [ + { + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "_setReserveFactor", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xfca7820b" + }, + { + "constant": true, + "inputs": [], + "name": "isCToken", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xfe9c44ae" + }, + { + "inputs": [ + { + "name": "underlying_", + "type": "address" + }, + { + "name": "comptroller_", + "type": "address" + }, + { + "name": "interestRateModel_", + "type": "address" + }, + { + "name": "initialExchangeRateMantissa_", + "type": "uint256" + }, + { + "name": "name_", + "type": "string" + }, + { + "name": "symbol_", + "type": "string" + }, + { + "name": "decimals_", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "interestAccumulated", + "type": "uint256" + }, + { + "indexed": false, + "name": "borrowIndex", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event", + "signature": "0x875352fb3fadeb8c0be7cbbe8ff761b308fa7033470cd0287f02f3436fd76cb9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "name": "mintAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "mintTokens", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event", + "signature": "0x4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "name": "redeemAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "redeemTokens", + "type": "uint256" + } + ], + "name": "Redeem", + "type": "event", + "signature": "0xe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "borrowAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "Borrow", + "type": "event", + "signature": "0x13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "accountBorrows", + "type": "uint256" + }, + { + "indexed": false, + "name": "totalBorrows", + "type": "uint256" + } + ], + "name": "RepayBorrow", + "type": "event", + "signature": "0x1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "liquidator", + "type": "address" + }, + { + "indexed": false, + "name": "borrower", + "type": "address" + }, + { + "indexed": false, + "name": "repayAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "cTokenCollateral", + "type": "address" + }, + { + "indexed": false, + "name": "seizeTokens", + "type": "uint256" + } + ], + "name": "LiquidateBorrow", + "type": "event", + "signature": "0x298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb52" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldPendingAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newPendingAdmin", + "type": "address" + } + ], + "name": "NewPendingAdmin", + "type": "event", + "signature": "0xca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldAdmin", + "type": "address" + }, + { + "indexed": false, + "name": "newAdmin", + "type": "address" + } + ], + "name": "NewAdmin", + "type": "event", + "signature": "0xf9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event", + "signature": "0x7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event", + "signature": "0xedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f926" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "oldReserveFactorMantissa", + "type": "uint256" + }, + { + "indexed": false, + "name": "newReserveFactorMantissa", + "type": "uint256" + } + ], + "name": "NewReserveFactor", + "type": "event", + "signature": "0xaaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "admin", + "type": "address" + }, + { + "indexed": false, + "name": "reduceAmount", + "type": "uint256" + }, + { + "indexed": false, + "name": "newTotalReserves", + "type": "uint256" + } + ], + "name": "ReservesReduced", + "type": "event", + "signature": "0x3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "error", + "type": "uint256" + }, + { + "indexed": false, + "name": "info", + "type": "uint256" + }, + { + "indexed": false, + "name": "detail", + "type": "uint256" + } + ], + "name": "Failure", + "type": "event", + "signature": "0x45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "amount", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + } + ], + "USDC": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x06fdde03" + }, + { + "constant": false, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + } + ], + "name": "allocateTo", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x08bca566" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x095ea7b3" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x18160ddd" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x23b872dd" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x313ce567" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0x66188463" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x70a08231" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0x95d89b41" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xa9059cbb" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_addedValue", + "type": "uint256" + } + ], + "name": "increaseApproval", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function", + "signature": "0xd73dd623" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function", + "signature": "0xdd62ed3e" + }, + { + "inputs": [ + { + "name": "_initialAmount", + "type": "uint256" + }, + { + "name": "_tokenName", + "type": "string" + }, + { + "name": "_decimalUnits", + "type": "uint8" + }, + { + "name": "_tokenSymbol", + "type": "string" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor", + "signature": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event", + "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event", + "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + } + ] +} \ No newline at end of file diff --git a/networks/ropsten.json b/networks/ropsten.json new file mode 100644 index 000000000..6ec3e4fc8 --- /dev/null +++ b/networks/ropsten.json @@ -0,0 +1,296 @@ +{ + "Contracts": { + "ZRX": "0x19787bcF63E228a6669d905E90aF397DCA313CFC", + "cUSDC": "0x43a1363AFB28235720FCbDF0C2dAb7759091F7e0", + "PriceOracle": "0x5dEA9621f23e79003eCC294b4cc1e4c9362dFECc", + "PriceOracleProxy": "0xc7E20CF485b8E0Bcec3e2fCc23e3aD93b1b0cB39", + "Maximillion": "0xE77Ce01B692FcF66E2F632e518b9449D18D582d8", + "cDAI": "0x2B536482a01E620eE111747F8334B395a42A555E", + "DAI": "0xB5E5D0F8C0cbA267CD3D7035d6AdC8eBA7Df7Cdd", + "StdComptroller": "0xe622DB19D5bf1F4e61Dd57FB11FE887100E5e59E", + "Unitroller": "0xb081cf57B1e422B3E627544Ec95992CBe8Eaf9cb", + "Comptroller": "0xb081cf57B1e422B3E627544Ec95992CBe8Eaf9cb", + "cBAT": "0x189CA88bE39C9c1B8c8dd437F5ff1DB1f584b14b", + "Base0bps_Slope2000bps": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa", + "BAT": "0x9636246bf34E688c6652Af544418B38eB51D2c43", + "cETH": "0x42a628e0c5F3767930097B34b08dCF77e78e4F2B", + "Base500bps_Slope1200bps": "0xbF7A7169562078c96f0eC1A8aFD6aE50f12e5A99", + "Base200bps_Slope3000bps": "0x6e894660985207feb7cf89Faf048998c71E8EE89", + "cREP": "0xA3C2c1618214549281E1b15dee9D682C8aa0DC1C", + "WBTC": "0xD83F707f003A1f0B1535028AB356FCE2667ab855", + "REP": "0x0A1e4D0B5c71B955c0a5993023fc48bA6E380496", + "cZRX": "0xDff375162cfE7D77473C1BEC4560dEDE974E138c", + "cWBTC": "0x06E728D7907C164649427D2ACFD4c81669D453Bf", + "USDC": "0x8a9447df1FB47209D36204e6D56767a33bf20f9f" + }, + "Blocks": { + "ZRX": 5970747, + "cUSDC": 5970770, + "PriceOracle": 5970733, + "PriceOracleProxy": 5970796, + "Maximillion": 5970773, + "cDAI": 5970763, + "DAI": 5970751, + "StdComptroller": 5970737, + "Unitroller": 5970735, + "cBAT": 5970761, + "Base0bps_Slope2000bps": 5970744, + "BAT": 5970749, + "cETH": 5970768, + "Base500bps_Slope1200bps": 5970743, + "Base200bps_Slope3000bps": 5970745, + "cREP": 5970764, + "WBTC": 5970757, + "REP": 5970753, + "cZRX": 5970759, + "cWBTC": 5970772, + "USDC": 5970755 + }, + "PriceOracle": { + "description": "Simple Price Oracle", + "address": "0x5dEA9621f23e79003eCC294b4cc1e4c9362dFECc" + }, + "Maximillion": { + "description": "Maximillion", + "cEtherAddress": "0x42a628e0c5F3767930097B34b08dCF77e78e4F2B", + "address": "0xE77Ce01B692FcF66E2F632e518b9449D18D582d8" + }, + "Unitroller": { + "description": "Unitroller", + "address": "0xb081cf57B1e422B3E627544Ec95992CBe8Eaf9cb" + }, + "Comptroller": { + "StdComptroller": { + "address": "0xe622DB19D5bf1F4e61Dd57FB11FE887100E5e59E", + "contract": "Comptroller", + "description": "Standard Comptroller Impl" + } + }, + "Constructors": { + "ZRX": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000002307800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a52580000000000000000000000000000000000000000000000000000000000", + "cUSDC": "0x0000000000000000000000008a9447df1fb47209d36204e6d56767a33bf20f9f000000000000000000000000b081cf57b1e422b3e627544ec95992cbe8eaf9cb0000000000000000000000005592ec0cfb4dbc12d3ab100b257153436a1f0fea0000000000000000000000000000000000000000000000000000b5e620f4800000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000016436f6d706f756e642055534420436f696e20f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000000000056355534443000000000000000000000000000000000000000000000000000000", + "PriceOracle": "0x", + "PriceOracleProxy": "0x000000000000000000000000b081cf57b1e422b3e627544ec95992cbe8eaf9cb0000000000000000000000005dea9621f23e79003ecc294b4cc1e4c9362dfecc00000000000000000000000042a628e0c5f3767930097b34b08dcf77e78e4f2b", + "Maximillion": "0x00000000000000000000000042a628e0c5f3767930097b34b08dcf77e78e4f2b", + "cDAI": "0x000000000000000000000000b5e5d0f8c0cba267cd3d7035d6adc8eba7df7cdd000000000000000000000000b081cf57b1e422b3e627544ec95992cbe8eaf9cb000000000000000000000000bf7a7169562078c96f0ec1a8afd6ae50f12e5a99000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000011436f6d706f756e642044616920f09f938800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046344414900000000000000000000000000000000000000000000000000000000", + "DAI": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000003446169000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034441490000000000000000000000000000000000000000000000000000000000", + "StdComptroller": "0x", + "Unitroller": "0x", + "cBAT": "0x0000000000000000000000009636246bf34e688c6652af544418b38eb51d2c43000000000000000000000000b081cf57b1e422b3e627544ec95992cbe8eaf9cb0000000000000000000000006e894660985207feb7cf89faf048998c71e8ee89000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000023436f6d706f756e6420426173696320417474656e74696f6e20546f6b656e20f09f9388000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046342415400000000000000000000000000000000000000000000000000000000", + "Base0bps_Slope2000bps": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c68af0bb140000", + "BAT": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000015426173696320417474656e74696f6e20546f6b656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000034241540000000000000000000000000000000000000000000000000000000000", + "cETH": "0x000000000000000000000000b081cf57b1e422b3e627544ec95992cbe8eaf9cb0000000000000000000000005592ec0cfb4dbc12d3ab100b257153436a1f0fea000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000013436f6d706f756e6420457468657220f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046345544800000000000000000000000000000000000000000000000000000000", + "Base500bps_Slope1200bps": "0x00000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000001aa535d3d0c0000", + "Base200bps_Slope3000bps": "0x00000000000000000000000000000000000000000000000000470de4df8200000000000000000000000000000000000000000000000000000429d069189e0000", + "cREP": "0x0000000000000000000000000a1e4d0b5c71b955c0a5993023fc48ba6e380496000000000000000000000000b081cf57b1e422b3e627544ec95992cbe8eaf9cb0000000000000000000000006e894660985207feb7cf89faf048998c71e8ee89000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000013436f6d706f756e6420417567757220f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046352455000000000000000000000000000000000000000000000000000000000", + "WBTC": "0x", + "REP": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000005417567757200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035245500000000000000000000000000000000000000000000000000000000000", + "cZRX": "0x00000000000000000000000019787bcf63e228a6669d905e90af397dca313cfc000000000000000000000000b081cf57b1e422b3e627544ec95992cbe8eaf9cb0000000000000000000000006e894660985207feb7cf89faf048998c71e8ee89000000000000000000000000000000000000000000a56fa5b99019a5c800000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010436f6d706f756e6420307820f09f9388000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004635a525800000000000000000000000000000000000000000000000000000000", + "cWBTC": "0x000000000000000000000000d83f707f003a1f0b1535028ab356fce2667ab855000000000000000000000000b081cf57b1e422b3e627544ec95992cbe8eaf9cb0000000000000000000000006e894660985207feb7cf89faf048998c71e8ee8900000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000019436f6d706f756e6420577261707065642042544320f09f93880000000000000000000000000000000000000000000000000000000000000000000000000000056357425443000000000000000000000000000000000000000000000000000000", + "USDC": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000855534420436f696e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045553444300000000000000000000000000000000000000000000000000000000" + }, + "Tokens": { + "ZRX": { + "description": "Standard", + "name": "0x", + "symbol": "ZRX", + "decimals": 18, + "contract": "FaucetToken", + "address": "0x19787bcF63E228a6669d905E90aF397DCA313CFC" + }, + "cUSDC": { + "name": "Compound USD Coin 📈", + "symbol": "cUSDC", + "decimals": 8, + "underlying": "0x8a9447df1FB47209D36204e6D56767a33bf20f9f", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000", + "address": "0x43a1363AFB28235720FCbDF0C2dAb7759091F7e0" + }, + "cDAI": { + "name": "Compound Dai 📈", + "symbol": "cDAI", + "decimals": 8, + "underlying": "0xB5E5D0F8C0cbA267CD3D7035d6AdC8eBA7Df7Cdd", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x2B536482a01E620eE111747F8334B395a42A555E" + }, + "DAI": { + "description": "Standard", + "name": "Dai", + "symbol": "DAI", + "decimals": 18, + "contract": "FaucetToken", + "address": "0xB5E5D0F8C0cbA267CD3D7035d6AdC8eBA7Df7Cdd" + }, + "cBAT": { + "name": "Compound Basic Attention Token 📈", + "symbol": "cBAT", + "decimals": 8, + "underlying": "0x9636246bf34E688c6652Af544418B38eB51D2c43", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x189CA88bE39C9c1B8c8dd437F5ff1DB1f584b14b" + }, + "BAT": { + "description": "NonStandard", + "name": "Basic Attention Token", + "symbol": "BAT", + "decimals": 18, + "contract": "FaucetNonStandardToken", + "address": "0x9636246bf34E688c6652Af544418B38eB51D2c43" + }, + "cETH": { + "name": "Compound Ether 📈", + "symbol": "cETH", + "decimals": 8, + "underlying": "", + "contract": "CEther", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x42a628e0c5F3767930097B34b08dCF77e78e4F2B" + }, + "cREP": { + "name": "Compound Augur 📈", + "symbol": "cREP", + "decimals": 8, + "underlying": "0x0A1e4D0B5c71B955c0a5993023fc48bA6E380496", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xA3C2c1618214549281E1b15dee9D682C8aa0DC1C" + }, + "WBTC": { + "description": "WBTC", + "name": "Wrapped BTC", + "symbol": "WBTC", + "decimals": 8, + "contract": "WBTCToken", + "address": "0xD83F707f003A1f0B1535028AB356FCE2667ab855" + }, + "REP": { + "description": "Standard", + "name": "Augur", + "symbol": "REP", + "decimals": 18, + "contract": "FaucetToken", + "address": "0x0A1e4D0B5c71B955c0a5993023fc48bA6E380496" + }, + "cZRX": { + "name": "Compound 0x 📈", + "symbol": "cZRX", + "decimals": 8, + "underlying": "0x19787bcF63E228a6669d905E90aF397DCA313CFC", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xDff375162cfE7D77473C1BEC4560dEDE974E138c" + }, + "cWBTC": { + "name": "Compound Wrapped BTC 📈", + "symbol": "cWBTC", + "decimals": 8, + "underlying": "0xD83F707f003A1f0B1535028AB356FCE2667ab855", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "20000000000000000", + "address": "0x06E728D7907C164649427D2ACFD4c81669D453Bf" + }, + "USDC": { + "description": "Standard", + "name": "USD Coin", + "symbol": "USDC", + "decimals": 6, + "contract": "FaucetToken", + "address": "0x8a9447df1FB47209D36204e6D56767a33bf20f9f" + } + }, + "cTokens": { + "cZRX": { + "name": "Compound 0x 📈", + "symbol": "cZRX", + "decimals": 8, + "underlying": "0x19787bcF63E228a6669d905E90aF397DCA313CFC", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xDff375162cfE7D77473C1BEC4560dEDE974E138c" + }, + "cBAT": { + "name": "Compound Basic Attention Token 📈", + "symbol": "cBAT", + "decimals": 8, + "underlying": "0x9636246bf34E688c6652Af544418B38eB51D2c43", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x189CA88bE39C9c1B8c8dd437F5ff1DB1f584b14b" + }, + "cDAI": { + "name": "Compound Dai 📈", + "symbol": "cDAI", + "decimals": 8, + "underlying": "0xB5E5D0F8C0cbA267CD3D7035d6AdC8eBA7Df7Cdd", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x2B536482a01E620eE111747F8334B395a42A555E" + }, + "cREP": { + "name": "Compound Augur 📈", + "symbol": "cREP", + "decimals": 8, + "underlying": "0x0A1e4D0B5c71B955c0a5993023fc48bA6E380496", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0xA3C2c1618214549281E1b15dee9D682C8aa0DC1C" + }, + "cETH": { + "name": "Compound Ether 📈", + "symbol": "cETH", + "decimals": 8, + "underlying": "", + "contract": "CEther", + "initial_exchange_rate_mantissa": "200000000000000000000000000", + "address": "0x42a628e0c5F3767930097B34b08dCF77e78e4F2B" + }, + "cUSDC": { + "name": "Compound USD Coin 📈", + "symbol": "cUSDC", + "decimals": 8, + "underlying": "0x8a9447df1FB47209D36204e6D56767a33bf20f9f", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "200000000000000", + "address": "0x43a1363AFB28235720FCbDF0C2dAb7759091F7e0" + }, + "cWBTC": { + "name": "Compound Wrapped BTC 📈", + "symbol": "cWBTC", + "decimals": 8, + "underlying": "0xD83F707f003A1f0B1535028AB356FCE2667ab855", + "contract": "CErc20", + "initial_exchange_rate_mantissa": "20000000000000000", + "address": "0x06E728D7907C164649427D2ACFD4c81669D453Bf" + } + }, + "InterestRateModel": { + "Base500bps_Slope1200bps": { + "name": "Base500bps_Slope1200bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=50000000000000000 multiplier=120000000000000000", + "base": "50000000000000000", + "slope": "120000000000000000", + "address": "0xbF7A7169562078c96f0eC1A8aFD6aE50f12e5A99" + }, + "Base0bps_Slope2000bps": { + "name": "Base0bps_Slope2000bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=0 multiplier=200000000000000000", + "base": "0", + "slope": "200000000000000000", + "address": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa" + }, + "Base200bps_Slope3000bps": { + "name": "Base200bps_Slope3000bps", + "contract": "WhitePaperInterestRateModel", + "description": "WhitePaper baseRate=20000000000000000 multiplier=300000000000000000", + "base": "20000000000000000", + "slope": "300000000000000000", + "address": "0x6e894660985207feb7cf89Faf048998c71E8EE89" + } + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 000000000..3776f9507 --- /dev/null +++ b/package.json @@ -0,0 +1,38 @@ +{ + "name": "compound-money-market", + "version": "0.2.1", + "description": "The Compound Protocol", + "main": "index.js", + "scripts": { + "console": "./script/console", + "coverage": "./script/coverage", + "deploy": "./scenario/script/repl -s ./script/scen/deploy.scen", + "lint": "./script/lint", + "repl": "./scenario/script/repl", + "scenario": "./script/scenario", + "test": "./script/test" + }, + "repository": "git@github.com:compound-finance/compound-protocol.git", + "author": "Compound Finance", + "license": "UNLICENSED", + "devDependencies": { + "bignumber.js": "8.0.1", + "ganache-cli": "^6.3.0", + "immutable": "^4.0.0-rc.12", + "mocha-junit-reporter": "^1.18.0", + "mocha-multi-reporters": "^1.1.7", + "request": "^2.88.0", + "solc": "0.5.8", + "solidity-coverage": "^0.6.3", + "solparse": "^2.2.8", + "truffle-config": "^1.1.17", + "truffle-flattener": "^1.3.0", + "truffle-resolver": "^5.0.0", + "web3": "^1.2.0" + }, + "dependencies": { + "ethlint": "^1.2.2", + "truffle": "^5.0.30", + "truffle-hdwallet-provider": "1.0.5" + } +} diff --git a/reporterConfig.json b/reporterConfig.json new file mode 100644 index 000000000..7a0c716ed --- /dev/null +++ b/reporterConfig.json @@ -0,0 +1,3 @@ +{ + "reporterEnabled": "spec, mocha-junit-reporter" +} \ No newline at end of file diff --git a/scenario/Grammar.pegjs b/scenario/Grammar.pegjs new file mode 100644 index 000000000..30bb16dbd --- /dev/null +++ b/scenario/Grammar.pegjs @@ -0,0 +1,318 @@ +// See: https://pegjs.org/online + +// Scenario Grammar + +{ + if (!Array.prototype.flat) { + Object.defineProperty(Array.prototype, 'flat', { + configurable: true, + value: function flat (x) { + var depth = isNaN(arguments[0]) ? 1 : Number(arguments[0]); + + return depth ? Array.prototype.reduce.call(this, function (acc, cur) { + if (Array.isArray(cur)) { + acc.push.apply(acc, flat.call(cur, depth - 1)); + } else { + acc.push(cur); + } + + return acc; + }, []) : Array.prototype.slice.call(this); + }, + writable: true + }); + } + + function getString(str) { + let val; + if (Array.isArray(str)) { + if (str.length !== 2 || str[0] !== 'String') { + throw new Error(`Expected string, got ${str}`); + } + + val = str[1]; + } else { + val = str; + } + + if (typeof val !== 'string') { + throw new Error(`Expected string, got ${val} (${typeof val})`); + } + + return val; + } + + function expandEvent(macros, step) { + const [eventName, ...eventArgs] = step; + + if (macros[eventName]) { + let expanded = expandMacro(macros[eventName], eventArgs); + + // Recursively expand steps + return expanded.map(event => expandEvent(macros, event)).flat(); + } else { + return [step]; + } + } + + function getArgValues(eventArgs, macroArgs) { + const eventArgNameMap = {}; + const eventArgIndexed = new Array(); + const argValues = {}; + let usedNamedArg = false; + let usedSplat = false; + + eventArgs.forEach((eventArg) => { + if (eventArg.argName) { + const {argName, argValue} = eventArg; + + eventArgNameMap[argName] = argValue; + usedNamedArg = true; + } else { + if (usedNamedArg) { + throw new Error(`Cannot use positional arg after named arg in macro invokation ${JSON.stringify(eventArgs)} looking at ${eventArg.toString()}`); + } + + eventArgIndexed.push(eventArg); + } + }); + + macroArgs.forEach(({arg, def, splat}, argIndex) => { + if (usedSplat) { + throw new Error("Cannot have arg after splat arg"); + } + + let val; + if (eventArgNameMap[arg] !== undefined) { + val = eventArgNameMap[arg]; + } else if (splat) { + val = eventArgIndexed.slice(argIndex); // Clear out any remaining args + usedSplat = true; + } else if (eventArgIndexed[argIndex] !== undefined) { + val = eventArgIndexed[argIndex]; + } else if (def !== undefined) { + val = def; + } else { + throw new Error("Macro cannot find arg value for " + arg); + } + argValues[arg] = val; + }); + + return argValues; + } + + function expandMacro(macro, eventArgs) { + const argValues = getArgValues(eventArgs, macro.args); + + function expandStep(step) { + return step.map((token) => { + if (argValues[token] !== undefined) { + return argValues[token]; + } else { + if (Array.isArray(token)) { + return expandStep(token); + } else { + return token; + } + } + }); + }; + + return macro.steps.map(expandStep); + } + + function addTopLevelEl(state, el) { + const macros = state.macros; + const tests = state.tests; + const pending = state.pending; + + switch (el.type) { + case 'macro': + const macro = {[el.name]: {args: el.args, steps: el.steps}}; + + return { + tests: tests, + macros: ({...macros, ...macro}) + }; + case 'test': + const steps = el.steps; + const expandedSteps = steps.map((step) => { + return expandEvent(macros, step) + }).flat(); + + const test = {[el.test]: expandedSteps}; + + return { + tests: {...tests, ...test}, + macros: macros + } + } + } +} + +tests + = values:( + head:top_level_el + tail:(line_separator t:top_level_el { return t; })* + { return tail.reduce((acc, el) => addTopLevelEl(acc, el), addTopLevelEl({macros: {}, tests: {}}, head)); } + )? + full_ws + { return values !== null ? values.tests : {}; } + +macros + = values:( + head:top_level_el + tail:(line_separator t:top_level_el { return t; })* + { return tail.reduce((acc, el) => addTopLevelEl(acc, el), addTopLevelEl({macros: {}, tests: {}}, head)); } + )? + full_ws + { return values !== null ? values.macros : {}; } + +top_level_el + = test + / macro + / gastest + / pending + / only + / skip + +test + = full_ws? "Test" ws name:string ws line_separator steps:steps? { return {type: 'test', test: getString(name), steps: steps}; } + +gastest + = full_ws? "GasTest" ws name:string ws line_separator steps:steps? { return {type: 'test', test: getString(name), steps: ["Gas"].concat(steps)}; } + +pending + = full_ws? "Pending" ws name:string ws line_separator steps:steps? { return {type: 'test', test: getString(name), steps: ["Pending"].concat(steps)}; } + +only + = full_ws? "Only" ws name:string ws line_separator steps:steps? { return {type: 'test', test: getString(name), steps: ["Only"].concat(steps)}; } + +skip + = full_ws? "Skip" ws name:string ws line_separator steps:steps? { return {type: 'test', test: getString(name), steps: ["Skip"].concat(steps)}; } + +macro + = full_ws? "Macro" ws name:token ws args:args? line_separator steps:steps { return {type: 'macro', name: getString(name), args: args || [], steps: steps}; } + +args + = args:( + head:arg + tail:(ws t:args { return t; })* + { return [head].concat(tail).filter((x) => !!x); } + ) + { return args !== null ? args.flat() : []; } + +arg + = splat:("..."?) arg:token def:(ws? "=" t:token ws? { return t; })? { return { arg, def, splat }; } + +token_set + = tokens:( + head:token + tail:(ws t:token_set { return t; })* + { return [head].concat(tail).filter((x) => !!x); } + ) + { return tokens !== null ? tokens.flat() : []; } + +steps + = steps:( + head:full_expr + tail:(line_separator step:full_expr { return step; })* + { return [head].concat(tail).filter((x) => !!x); } + )? + { return steps !== null ? steps : []; } + +full_expr + = tab_separator step:step { return step; } + / comment { return null; } + / tab_separator ws { return null; } + +step + = val:expr comment? { return val; } + / comment { return null; } + / tab_separator? ws { return null; } + +expr + = ( + head:token + tail:(ws continuation? value:expr { return value })* + { return [head].concat(tail.flat(1)); } + ) + / begin_compound inner:expr end_compound { return [inner]; } + / begin_list inner:list_inner? end_list { return [["List"].concat((inner || []).flat())] }; + +comment + = ws "--" [^\n]* { return null; } + / ws "#" [^\n]* { return null; } + +token = + token1:simple_token ":" token2:simple_token { return {argName: token1, argValue: token2} } + / simple_token + +simple_token = + hex + / number + / ( t:([A-Za-z0-9_]+) { return t.join("") } ) + / string + +hex = hex:("0x" [0-9a-fA-F]+) { return ["Hex", hex.flat().flat().join("")] } +number = + n:(("-" / "+")? [0-9]+ ("." [0-9]+)? ("e" "-"? [0-9]+)?) { return ["Exactly", n.flat().flat().join("")] } + +list_inner + = ( + head:expr + tail:(ws? value:list_inner { return value })* + { return [head].concat(tail.flat()); } + ) + +begin_compound = ws "(" ws +end_compound = ws ")" ws + +begin_list = ws "[" ws +end_list = ws "]" ws + +line_separator = "\r"?"\n" +tab_separator = "\t" + / " " + +continuation = "\\" line_separator tab_separator tab_separator + +ws "whitespace" = [ \t]* +full_ws = comment full_ws + / [ \t\r\n] full_ws? + +string "string" + = quotation_mark chars:char* quotation_mark { return ["String", chars.join("")]; } + +char + = unescaped + / escape + sequence:( + '"' + / "\\" + / "/" + / "b" { return "\b"; } + / "f" { return "\f"; } + / "n" { return "\n"; } + / "r" { return "\r"; } + / "t" { return "\t"; } + / "u" digits:$(HEXDIG HEXDIG HEXDIG HEXDIG) { + return String.fromCharCode(parseInt(digits, 16)); + } + ) + { return sequence; } + +escape + = "\\" + +quotation_mark + = '"' + +unescaped + = [^\0-\x1F\x22\x5C] + +// ----- Core ABNF Rules ----- + +// See RFC 4234, Appendix B (http://tools.ietf.org/html/rfc4234). +DIGIT = [0-9] +HEXDIG = [0-9a-f]i \ No newline at end of file diff --git a/scenario/SCENARIO.md b/scenario/SCENARIO.md new file mode 100644 index 000000000..3ee226eaf --- /dev/null +++ b/scenario/SCENARIO.md @@ -0,0 +1,219 @@ + +# Types +* `name:` - Helper to describe arguments with names, not actually input this way +* `` - `True` or `False` +* `` - A standard number (e.g. `5` or `6.0` or `10.0e18`) +* `` - The local name for a given cToken when created, e.g. `cZRX` +* `` - One of: `Admin, Bank, Geoff, Torrey, Robert, Coburn, Jared` +* `` - A string, may be quoted but does not have to be if a single-word (e.g. `"Mint"` or `Mint`) +* `
` - TODO +* `` - See assertions below. + +# Events + +## Core Events + +* "History n:=5" - Prints history of actions + * E.g. "History" + * E.g. "History 10" +* `Read ...` - Reads given value and prints result + * E.g. `Read CToken cBAT ExchangeRateStored` - Returns exchange rate of cBAT +* `Assert ` - Validates given assertion, raising an exception if assertion fails + * E.g. `Assert Equal (Erc20 BAT TokenBalance Geoff) (Exactly 5.0)` - Returns exchange rate of cBAT +* `FastForward n: Blocks` - For `CTokenScenario`, moves the block number forward n blocks. Note: in `CTokenScenario` the current block number is mocked (starting at 100000). Thus, this is the only way for the protocol to see a higher block number (for accruing interest). + * E.g. `FastForward 5 Blocks` - Move block number forward 5 blocks. +* `Inspect` - Prints debugging information about the world +* `Debug message:` - Same as inspect but prepends with a string +* `From ` - Runs event as the given user + * E.g. `From Geoff (CToken cZRX Mint 5e18)` +* `Invariant ` - Adds a new invariant to the world which is checked after each transaction + * E.g. `Invariant Static (CToken cZRX TotalSupply)` +* `WipeInvariants` - Removes all invariants. +* `Comptroller ` - Runs given Comptroller event + * E.g. `Comptroller _setReserveFactor 0.5` +* `CToken ` - Runs given CToken event + * E.g. `CToken cZRX Mint 5e18` +* `Erc20 ` - Runs given Erc20 event + * E.g. `Erc20 ZRX Facuet Geoff 5e18` +* `InterestRateModel ...event` - Runs given interest rate model event + * E.g. `InterestRateModel Deployed (Fixed 0.5)` +* `PriceOracle ` - Runs given Price Oracle event + * E.g. `PriceOracle SetPrice cZRX 1.5` + +## Comptroller Events + +* "Comptroller Deploy ...comptrollerParams" - Generates a new Comptroller + * E.g. "Comptroller Deploy Scenario (PriceOracle Address) 0.1 10" +* `Comptroller SetPaused action: paused:` - Pauses or unpaused given cToken function (e.g. Mint) + * E.g. `Comptroller SetPaused Mint True` +* `Comptroller SupportMarket ` - Adds support in the Comptroller for the given cToken + * E.g. `Comptroller SupportMarket cZRX` +* `Comptroller EnterMarkets ...` - User enters the given markets + * E.g. `Comptroller EnterMarkets Geoff cZRX cETH` +* `Comptroller SetMaxAssets ` - Sets (or resets) the max allowed asset count + * E.g. `Comptroller SetMaxAssets 4` +* `CToken SetOracle oracle:` - Sets the oracle + * E.g. `Comptroller SetOracle (Fixed 1.5)` +* `Comptroller SetCollateralFactor ` - Sets the collateral factor for given cToken to number + * E.g. `Comptroller SetCollateralFactor cZRX 0.1` +* `FastForward n: Blocks` - Moves the block number forward `n` blocks. Note: in `CTokenScenario` and `ComptrollerScenario` the current block number is mocked (starting at 100000). This is the only way for the protocol to see a higher block number (for accruing interest). + * E.g. `Comptroller FastForward 5 Blocks` - Move block number forward 5 blocks. + +## cToken Events + +* `CToken Deploy name: underlying: comptroller: interestRateModel: initialExchangeRate: decimals:` - Generates a new comptroller and sets to world global + * E.g. `CToken Deploy cZRX (Erc20 ZRX Address) (Comptroller Address) (InterestRateModel Address) 1.0 18` +* `CToken AccrueInterest` - Accrues interest for given token + * E.g. `CToken cZRX AccrueInterest` +* `CToken Mint amount:` - Mints the given amount of cToken as specified user + * E.g. `CToken cZRX Mint Geoff 1.0` +* `CToken Redeem amount:` - Redeems the given amount of cToken as specified user + * E.g. `CToken cZRX Redeem Geoff 1.0e18` +* `CToken Borrow amount:` - Borrows the given amount of this cToken as specified user + * E.g. `CToken cZRX Borrow Geoff 1.0e18` +* `CToken ReduceReserves amount:` - Reduces the reserves of the cToken + * E.g. `CToken cZRX ReduceReserves 1.0e18` +* `CToken SetReserveFactor amount:` - Sets the reserve factor for the cToken + * E.g. `CToken cZRX SetReserveFactor 0.1` +* `CToken SetInterestRateModel interestRateModel:` - Sets the interest rate model for the given cToken + * E.g. `CToken cZRX SetInterestRateModel (Fixed 1.5)` +* `CToken SetComptroller comptroller:` - Sets the comptroller for the given cToken + * E.g. `CToken cZRX SetComptroller Comptroller` +* `CToken Mock variable: value:` - Mocks a given value on cToken. Note: value must be a supported mock and this will only work on a CTokenScenario contract. + * E.g. `CToken cZRX Mock totalBorrows 5.0e18` + * E.g. `CToken cZRX Mock totalReserves 0.5e18` + +## Erc-20 Events + +* `Erc20 Deploy name:` - Generates a new ERC-20 token by name + * E.g. `Erc20 Deploy ZRX` +* `Erc20 Approve
` - Adds an allowance between user and address + * E.g. `Erc20 ZRX Approve Geoff cZRX 1.0e18` +* `Erc20 Faucet
` - Adds an arbitrary balance to given user + * E.g. `Erc20 ZRX Facuet Geoff 1.0e18` + +## Price Oracle Events + +* `Deploy` - Generates a new price oracle (note: defaults to (Fixed 1.0)) + * E.g. `PriceOracle Deploy (Fixed 1.0)` + * E.g. `PriceOracle Deploy Simple` + * E.g. `PriceOracle Deploy NotPriceOracle` +* `SetPrice ` - Sets the per-ether price for the given cToken + * E.g. `PriceOracle SetPrice cZRX 1.0` + +## Interest Rate Model Events + +## Deploy + +* `Deploy params:` - Generates a new interest rate model (note: defaults to (Fixed 0.25)) + * E.g. `InterestRateModel Deploy (Fixed 0.5)` + * E.g. `InterestRateModel Deploy Whitepaper` + +# Values + +## Core Values + +* `True` - Returns true +* `False` - Returns false +* `Zero` - Returns 0 +* `Some` - Returns 100e18 +* `Little` - Returns 100e10 +* `Exactly ` - Returns a strict numerical value + * E.g. `Exactly 5.0` +* `Exp ` - Returns the mantissa for a given exp + * E.g. `Exp 5.5` +* `Precisely ` - Matches a number to given number of significant figures + * E.g. `Exactly 5.1000` - Matches to 5 sig figs +* `Anything` - Matches anything +* `Nothing` - Matches nothing +* `Default value: default:` - Returns value if truthy, otherwise default. Note: this does short-circuit +* `LastContract` - Returns the address of last constructed contract +* `User <...>` - Returns User value (see below) +* `Comptroller <...>` - Returns Comptroller value (see below) +* `CToken <...>` - Returns CToken value (see below) +* `Erc20 <...>` - Returns Erc20 value (see below) +* `InterestRateModel <...>` - Returns InterestRateModel value (see below) +* `PriceOracle <...>` - Returns PriceOracle value (see below) + +## User Values + +* `User Address` - Returns address of user + * E.g. `User Geoff Address` - Returns Geoff's address + +## Comptroller Values + +* `Comptroller Liquidity ` - Returns a given user's trued up liquidity + * E.g. `Comptroller Liquidity Geoff` +* `Comptroller MembershipLength ` - Returns a given user's length of membership + * E.g. `Comptroller MembershipLength Geoff` +* `Comptroller CheckMembership ` - Returns one if user is in asset, zero otherwise. + * E.g. `Comptroller CheckMembership Geoff cZRX` +* "Comptroller CheckListed " - Returns true if market is listed, false otherwise. + * E.g. "Comptroller CheckListed cZRX" + +## CToken Values +* `CToken UnderlyingBalance ` - Returns a user's underlying balance (based on given exchange rate) + * E.g. `CToken cZRX UnderlyingBalance Geoff` +* `CToken BorrowBalance ` - Returns a user's borrow balance (including interest) + * E.g. `CToken cZRX BorrowBalance Geoff` +* `CToken TotalBorrowBalance` - Returns the cToken's total borrow balance + * E.g. `CToken cZRX TotalBorrowBalance` +* `CToken Reserves` - Returns the cToken's total reserves + * E.g. `CToken cZRX Reserves` +* `CToken Comptroller` - Returns the cToken's comptroller + * E.g. `CToken cZRX Comptroller` +* `CToken PriceOracle` - Returns the cToken's price oracle + * E.g. `CToken cZRX PriceOracle` +* `CToken ExchangeRateStored` - Returns the cToken's exchange rate (based on balances stored) + * E.g. `CToken cZRX ExchangeRateStored` +* `CToken ExchangeRate` - Returns the cToken's current exchange rate + * E.g. `CToken cZRX ExchangeRate` + +## Erc-20 Values + +* `Erc20 Address` - Returns address of ERC-20 contract + * E.g. `Erc20 ZRX Address` - Returns ZRX's address +* `Erc20 Name` - Returns name of ERC-20 contract + * E.g. `Erc20 ZRX Address` - Returns ZRX's name +* `Erc20 Symbol` - Returns symbol of ERC-20 contract + * E.g. `Erc20 ZRX Symbol` - Returns ZRX's symbol +* `Erc20 Decimals` - Returns number of decimals in ERC-20 contract + * E.g. `Erc20 ZRX Decimals` - Returns ZRX's decimals +* `Erc20 TotalSupply` - Returns the ERC-20 token's total supply + * E.g. `Erc20 ZRX TotalSupply` + * E.g. `Erc20 cZRX TotalSupply` +* `Erc20 TokenBalance
` - Returns the ERC-20 token balance of a given address + * E.g. `Erc20 ZRX TokenBalance Geoff` - Returns a user's ZRX balance + * E.g. `Erc20 cZRX TokenBalance Geoff` - Returns a user's cZRX balance + * E.g. `Erc20 ZRX TokenBalance cZRX` - Returns cZRX's ZRX balance +* `Erc20 Allowance owner:
spender:
` - Returns the ERC-20 allowance from owner to spender + * E.g. `Erc20 ZRX Allowance Geoff Torrey` - Returns the ZRX allowance of Geoff to Torrey + * E.g. `Erc20 cZRX Allowance Geoff Coburn` - Returns the cZRX allowance of Geoff to Coburn + * E.g. `Erc20 ZRX Allowance Geoff cZRX` - Returns the ZRX allowance of Geoff to the cZRX cToken + +## PriceOracle Values + +* `Address` - Gets the address of the global price oracle +* `Price asset:
` - Gets the price of the given asset + +## Interest Rate Model Values + +* `Address` - Gets the address of the global interest rate model + +# Assertions + +* `Equal given: expected:` - Asserts that given matches expected. + * E.g. `Assert Equal (Exactly 0) Zero` + * E.g. `Assert Equal (CToken cZRX TotalSupply) (Exactly 55)` + * E.g. `Assert Equal (CToken cZRX Comptroller) (Comptroller Address)` +* `True given:` - Asserts that given is true. + * E.g. `Assert True (Comptroller CheckMembership Geoff cETH)` +* `False given:` - Asserts that given is false. + * E.g. `Assert False (Comptroller CheckMembership Geoff cETH)` +* `Failure error: info: detail:` - Asserts that last transaction had a graceful failure with given error, info and detail. + * E.g. `Assert Failure UNAUTHORIZED SUPPORT_MARKET_OWNER_CHECK` + * E.g. `Assert Failure MATH_ERROR MINT_CALCULATE_BALANCE 5` +* `Revert` - Asserts that the last transaction reverted. +* `Success` - Asserts that the last transaction completed successfully (that is, did not revert nor emit graceful failure). +* `Log name: ((key: value:) ...)` - Asserts that last transaction emitted log with given name and key-value pairs. + * E.g. `Assert Log Minted (("account" (User Geoff address)) ("amount" (Exactly 55)))` diff --git a/scenario/package.json b/scenario/package.json new file mode 100644 index 000000000..37d5c8b5c --- /dev/null +++ b/scenario/package.json @@ -0,0 +1,30 @@ +{ + "name": "compound-money-market", + "version": "0.2.1", + "description": "The Compound Money Market", + "main": "index.js", + "scripts": { + "build": "./script/webpack" + }, + "repository": "git@github.com:compound-finance/money-market.git", + "author": "Compound Finance", + "license": "UNLICENSED", + "devDependencies": { + "request": "^2.88.0", + "solparse": "^2.2.8", + "ts-loader": "^5.3.3", + "ts-pegjs": "^0.2.2", + "typescript": "^3.3.3", + "webpack": "^4.29.6", + "webpack-bundle-analyzer": "^3.1.0", + "webpack-cli": "^3.3.0" + }, + "dependencies": { + "bignumber.js": "8.0.1", + "ethers": "^4.0.0-beta.1", + "immutable": "^4.0.0-rc.12", + "truffle-flattener": "^1.3.0", + "truffle-hdwallet-provider": "1.0.5", + "web3": "1.0.0-beta.37" + } +} diff --git a/scenario/script/generate_parser b/scenario/script/generate_parser new file mode 100755 index 000000000..1d889fcdd --- /dev/null +++ b/scenario/script/generate_parser @@ -0,0 +1,11 @@ +#!/bin/bash + +dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +scenario_dir="$(cd $dir/.. && pwd)" + +"$scenario_dir/node_modules/.bin/pegjs" \ + --plugin "$scenario_dir/node_modules/ts-pegjs" \ + -o "$scenario_dir/src/Parser.ts" \ + --cache \ + --allowed-start-rules tests,step,macros \ + "$scenario_dir/Grammar.pegjs" diff --git a/scenario/script/repl b/scenario/script/repl new file mode 100755 index 000000000..28f51b39e --- /dev/null +++ b/scenario/script/repl @@ -0,0 +1,78 @@ +#!/usr/bin/env sh + +set -eo + +dir=`dirname $0` +tsc_root="$(cd "$dir/.." && pwd)" +proj_root="$(cd "$dir/../.." && pwd)" +networks_root="$(cd "$dir/../../networks" && pwd)" +test_root="$(cd "$dir/../../test" && pwd)" +contracts_root="$(cd "$dir/../../contracts" && pwd)" +network=${NETWORK:-development} +script="$SCRIPT" +verbose="$VERBOSE" +dry_run="$DRY_RUN" +no_tsc="$NO_TSC" + +usage() { echo "$0 usage:" && grep ".)\ #" $0; exit 0; } +while getopts ":hdn:e:s:vt" arg; do + case $arg in + c) # Don't compile + no_compile="true" + ;; + d) # Dry run + dry_run="true" + ;; + e) # Add variables for script (key=value,key2=value2) + env_vars="$OPTARG" + ;; + n) # Specify network + network=$OPTARG + ;; + s) # Specify a script to run + if [[ "$OSTYPE" == "darwin"* ]]; then + # Darwin doesn't support readlink -f to get absolute path... + script=$OPTARG + else + script=$(readlink -f "$OPTARG") + fi + + [ ! -f "$script" ] \ + && echo "Cannot find script $script" \ + && exit 1 + ;; + t) # Don't build TSC + no_tsc="true" + ;; + + v) # Verbose + verbose="true" + ;; + + h | *) # Display help. + usage + exit 0 + ;; + esac +done + +if [ $network = "test" -o $network = "development" -o -n "$add_test_contracts" ]; then + function cleanup { + mv "$contracts_root/test" "$test_root/contracts" + } + + trap cleanup EXIT + + mv "$test_root/contracts" "$contracts_root/test" + + # Compile with test contracts + [[ -z $no_compile ]] && solc --combined-json bin,abi --optimize contracts/*.sol contracts/**/*.sol --allow-paths ./contracts,./contracts/test > networks/${network}-contracts.json +else + # Compile without test contracts + [[ -z $no_compile ]] && solc --combined-json bin,abi --optimize contracts/*.sol > networks/${network}-contracts.json +fi + +[[ ! -d ./.tsbuilt || -z $no_tsc ]] && . "$dir/tsc" + + +proj_root="$proj_root" env_vars="$env_vars" dry_run="$dry_run" script="$script" network="$network" verbose="$verbose" npx truffle exec --network "$network" "$tsc_root/.tsbuilt/Repl.js" diff --git a/scenario/script/tsc b/scenario/script/tsc new file mode 100755 index 000000000..5d45f8aff --- /dev/null +++ b/scenario/script/tsc @@ -0,0 +1,14 @@ +#!/bin/sh + +set -eo + +dir=`dirname $0` +scenario_dir="$(cd $dir/.. && pwd)" + +if [ ! -d "$scenario_dir/node_modules" ]; then + echo "Getting scenario packages..." + cd "$scenario_dir" && yarn +fi + +echo "Building Scenario Runner..." +cd "$scenario_dir" && node "$scenario_dir/node_modules/.bin/tsc" ${TSC_ARGS-"--skipLibCheck"} diff --git a/scenario/script/webpack b/scenario/script/webpack new file mode 100755 index 000000000..4e7c69ad0 --- /dev/null +++ b/scenario/script/webpack @@ -0,0 +1,16 @@ +#!/bin/bash + +dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +scenario_dir="$(cd $dir/.. && pwd)" + +cd "$scenario_dir" && + mkdir -p ./build && + ./node_modules/.bin/webpack \ + --mode production \ + --config ./webpack.config.js \ + --entry ./src/Web.ts \ + --module-bind 'ts=ts-loader' \ + --module-bind 'exports-loader?parse' \ + --resolve-extensions ".ts,.js" \ + --output-library-target window \ + --output ./build/scenario.js diff --git a/scenario/src/Accounts.ts b/scenario/src/Accounts.ts new file mode 100644 index 000000000..2845c5d75 --- /dev/null +++ b/scenario/src/Accounts.ts @@ -0,0 +1,48 @@ +import {World} from './World'; +import {Map} from 'immutable'; + +export const accountMap = { + "default": 0, + "root": 0, + "admin": 0, + "first": 0, + + "bank": 1, + "second": 1, + + "geoff": 2, + "third": 2, + + "torrey": 3, + "fourth": 3, + + "robert": 4, + "fifth": 4, + + "coburn": 5, + "sixth": 5, + + "jared": 6, + "seventh": 6 +}; + +export interface Account { + name: string + address: string +} + +export type Accounts = Map + +export function accountAliases(index: number): string[] { + return Object.entries(accountMap).filter(([k,v]) => v === index).map(([k,v]) => k); +} + +export function loadAccounts(accounts: string[]): Accounts { + return Object.entries(accountMap).reduce((acc, [name, index]) => { + if (accounts[index]) { + return acc.set(name, { name: name, address: accounts[index] }); + } else { + return acc; + } + }, >Map({})); +} diff --git a/scenario/src/Action.ts b/scenario/src/Action.ts new file mode 100644 index 000000000..81eaabc11 --- /dev/null +++ b/scenario/src/Action.ts @@ -0,0 +1,15 @@ +import {Invokation} from './Invokation'; + +export class Action { + log: string; + invokation: Invokation; + + constructor(log: string, invokation: Invokation) { + this.log = log; + this.invokation = invokation; + } + + toString() { + return `Action: log=${this.log}, result=${this.invokation.toString()}`; + } +} diff --git a/scenario/src/Artifact.ts b/scenario/src/Artifact.ts new file mode 100644 index 000000000..3083e932e --- /dev/null +++ b/scenario/src/Artifact.ts @@ -0,0 +1,5 @@ + +export interface Artifact {} +export interface Artifacts { + require(file: string): Artifact +} diff --git a/scenario/src/Assert.ts b/scenario/src/Assert.ts new file mode 100644 index 000000000..e604371f3 --- /dev/null +++ b/scenario/src/Assert.ts @@ -0,0 +1,21 @@ +export interface Assert { + fail(x: any, y: any, reason: string) + equal(x: any, y: any, reason: string) + deepEqual(x: any, y: any, reason: string) +} + +export const throwAssert: Assert = { + fail: (x, y, reason) => { + throw new Error(reason) + }, + equal: (x, y, reason) => { + if (x != y) { + throw new Error(reason); + } + }, + deepEqual: (x, y, reason) => { + if (JSON.stringify(x) != JSON.stringify(y)) { + throw new Error(reason); + } + } +}; diff --git a/scenario/src/Builder/CTokenBuilder.ts b/scenario/src/Builder/CTokenBuilder.ts new file mode 100644 index 000000000..d90bf2253 --- /dev/null +++ b/scenario/src/Builder/CTokenBuilder.ts @@ -0,0 +1,244 @@ +import {Event} from '../Event'; +import {addAction, World} from '../World'; +import {CToken} from '../Contract/CToken'; +import {Invokation, invoke} from '../Invokation'; +import { + getAddressV, + getExpNumberV, + getNumberV, + getStringV +} from '../CoreValue'; +import { + AddressV, + NumberV, + StringV +} from '../Value'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {storeAndSaveContract} from '../Networks'; +import {getContract, getTestContract} from '../Contract'; + +const CErc20Contract = getContract('CErc20'); +const CEtherContract = getContract('CEther'); +const CErc20ScenarioContract = getTestContract('CErc20Scenario'); +const CEtherScenarioContract = getTestContract('CEtherScenario'); +const CEvilContract = getTestContract('CEvil'); + +export interface TokenData { + invokation: Invokation + name: string + symbol: string + decimals: number + underlying: string + address?: string + contract: string + initial_exchange_rate_mantissa: string +} + +export async function buildCToken(world: World, from: string, params: Event): Promise<{world: World, cToken: CToken, tokenData: TokenData}> { + const fetchers = [ + new Fetcher<{symbol: StringV, name: StringV, decimals: NumberV, underlying: AddressV, comptroller: AddressV, interestRateModel: AddressV, initialExchangeRate: NumberV}, TokenData>(` + #### Scenario + + * "Scenario symbol: name: underlying:
comptroller:
interestRateModel:
initialExchangeRate: decimals: " - A CToken Scenario for local testing + * E.g. "CToken Deploy Scenario cZRX (Erc20 ZRX Address) (Comptroller Address) (InterestRateModel Address) 1.0 8" + `, + "Scenario", + [ + new Arg("symbol", getStringV), + new Arg("name", getStringV), + new Arg("underlying", getAddressV), + new Arg("comptroller", getAddressV), + new Arg("interestRateModel", getAddressV), + new Arg("initialExchangeRate", getExpNumberV), + new Arg("decimals", getNumberV) + ], + async (world, {symbol, name, underlying, comptroller, interestRateModel, initialExchangeRate, decimals}) => { + return { + invokation: await CErc20ScenarioContract.deploy(world, from, [underlying.val, comptroller.val, interestRateModel.val, initialExchangeRate.val, name.val, symbol.val, decimals.val]), + name: name.val, + symbol: symbol.val, + decimals: decimals.toNumber(), + underlying: underlying.val, + contract: 'CErc20Scenario', + initial_exchange_rate_mantissa: initialExchangeRate.encode().toString() + }; + } + ), + new Fetcher<{symbol: StringV, name: StringV, decimals: NumberV, comptroller: AddressV, interestRateModel: AddressV, initialExchangeRate: NumberV}, TokenData>(` + #### CEtherScenario + + * "CEtherScenario symbol: name: comptroller:
interestRateModel:
initialExchangeRate: decimals: " - A CToken Scenario for local testing + * E.g. "CToken Deploy CEtherScenario (Erc20 ZRX Address) (Comptroller Address) (InterestRateModel Address) 1.0 8" + `, + "CEtherScenario", + [ + new Arg("symbol", getStringV), + new Arg("name", getStringV), + new Arg("comptroller", getAddressV), + new Arg("interestRateModel", getAddressV), + new Arg("initialExchangeRate", getExpNumberV), + new Arg("decimals", getNumberV) + ], + async (world, {symbol, name, comptroller, interestRateModel, initialExchangeRate, decimals}) => { + return { + invokation: await CEtherScenarioContract.deploy(world, from, [name.val, symbol.val, decimals.val, comptroller.val, interestRateModel.val, initialExchangeRate.val]), + name: name.val, + symbol: symbol.val, + decimals: decimals.toNumber(), + underlying: "", + contract: 'CEtherScenario', + initial_exchange_rate_mantissa: initialExchangeRate.encode().toString() + }; + } + ), + new Fetcher<{symbol: StringV, name: StringV, decimals: NumberV, comptroller: AddressV, interestRateModel: AddressV, initialExchangeRate: NumberV}, TokenData>(` + #### CEther + + * "CEther symbol: name: comptroller:
interestRateModel:
initialExchangeRate: decimals: " - A CToken Scenario for local testing + * E.g. "CToken Deploy CEther cETH (Comptroller Address) (InterestRateModel Address) 1.0 8" + `, + "CEther", + [ + new Arg("symbol", getStringV), + new Arg("name", getStringV), + new Arg("comptroller", getAddressV), + new Arg("interestRateModel", getAddressV), + new Arg("initialExchangeRate", getExpNumberV), + new Arg("decimals", getNumberV) + ], + async (world, {symbol, name, comptroller, interestRateModel, initialExchangeRate, decimals}) => { + return { + invokation: await CEtherContract.deploy(world, from, [comptroller.val, interestRateModel.val, initialExchangeRate.val, name.val, symbol.val, decimals.val]), + name: name.val, + symbol: symbol.val, + decimals: decimals.toNumber(), + underlying: "", + contract: 'CEther', + initial_exchange_rate_mantissa: initialExchangeRate.encode().toString() + }; + } + ), + new Fetcher<{symbol: StringV, name: StringV, decimals: NumberV, underlying: AddressV, comptroller: AddressV, interestRateModel: AddressV, initialExchangeRate: NumberV}, TokenData>(` + #### CErc20 + + * "CErc20 symbol: name: underlying:
comptroller:
interestRateModel:
initialExchangeRate: decimals: " - A official CToken contract + * E.g. "CToken Deploy CErc20 cZRX (Erc20 ZRX Address) (Comptroller Address) (InterestRateModel Address) 1.0 8" + `, + "CErc20", + [ + new Arg("symbol", getStringV), + new Arg("name", getStringV), + new Arg("underlying", getAddressV), + new Arg("comptroller", getAddressV), + new Arg("interestRateModel", getAddressV), + new Arg("initialExchangeRate", getExpNumberV), + new Arg("decimals", getNumberV) + ], + async (world, {symbol, name, underlying, comptroller, interestRateModel, initialExchangeRate, decimals}) => { + return { + invokation: await CErc20Contract.deploy(world, from, [underlying.val, comptroller.val, interestRateModel.val, initialExchangeRate.val, name.val, symbol.val, decimals.val]), + name: name.val, + symbol: symbol.val, + decimals: decimals.toNumber(), + underlying: underlying.val, + contract: 'CErc20', + initial_exchange_rate_mantissa: initialExchangeRate.encode().toString() + }; + } + ), + new Fetcher<{symbol: StringV, name: StringV, decimals: NumberV, underlying: AddressV, comptroller: AddressV, interestRateModel: AddressV, initialExchangeRate: NumberV}, TokenData>(` + #### CEvil + + * "CEvil symbol: name: underlying:
comptroller:
interestRateModel:
initialExchangeRate: decimals: " - A malicious CToken contract + * E.g. "CToken Deploy CEvil cEVL (Erc20 ZRX Address) (Comptroller Address) (InterestRateModel Address) 1.0 8" + `, + "CEvil", + [ + new Arg("symbol", getStringV), + new Arg("name", getStringV), + new Arg("underlying", getAddressV), + new Arg("comptroller", getAddressV), + new Arg("interestRateModel", getAddressV), + new Arg("initialExchangeRate", getExpNumberV), + new Arg("decimals", getNumberV) + ], + async (world, {symbol, name, underlying, comptroller, interestRateModel, initialExchangeRate, decimals}) => { + return { + invokation: await CEvilContract.deploy(world, from, [underlying.val, comptroller.val, interestRateModel.val, initialExchangeRate.val, name.val, symbol.val, decimals.val]), + name: name.val, + symbol: symbol.val, + decimals: decimals.toNumber(), + underlying: underlying.val, + contract: 'CEvil', + initial_exchange_rate_mantissa: initialExchangeRate.encode().toString() + }; + } + ), + new Fetcher<{symbol: StringV, name: StringV, decimals: NumberV, underlying: AddressV, comptroller: AddressV, interestRateModel: AddressV, initialExchangeRate: NumberV}, TokenData>(` + #### Standard + + * "symbol: name: underlying:
comptroller:
interestRateModel:
initialExchangeRate: decimals: " - A official CToken contract + * E.g. "CToken Deploy cZRX (Erc20 ZRX Address) (Comptroller Address) (InterestRateModel Address) 1.0 8" + `, + "Standard", + [ + new Arg("symbol", getStringV), + new Arg("name", getStringV), + new Arg("underlying", getAddressV), + new Arg("comptroller", getAddressV), + new Arg("interestRateModel", getAddressV), + new Arg("initialExchangeRate", getExpNumberV), + new Arg("decimals", getNumberV) + ], + async (world, {symbol, name, underlying, comptroller, interestRateModel, initialExchangeRate, decimals}) => { + // Note: we're going to use the scenario contract as the standard deployment on local networks + if (world.isLocalNetwork()) { + return { + invokation: await CErc20ScenarioContract.deploy(world, from, [underlying.val, comptroller.val, interestRateModel.val, initialExchangeRate.val, name.val, symbol.val, decimals.val]), + name: name.val, + symbol: symbol.val, + decimals: decimals.toNumber(), + underlying: underlying.val, + contract: 'CErc20Scenario', + initial_exchange_rate_mantissa: initialExchangeRate.encode().toString() + }; + } else { + return { + invokation: await CErc20Contract.deploy(world, from, [underlying.val, comptroller.val, interestRateModel.val, initialExchangeRate.val, name.val, symbol.val, decimals.val]), + name: name.val, + symbol: symbol.val, + decimals: decimals.toNumber(), + underlying: underlying.val, + contract: 'CErc20', + initial_exchange_rate_mantissa: initialExchangeRate.encode().toString() + }; + } + }, + {catchall: true} + ) + ]; + + let tokenData = await getFetcherValue("DeployCToken", fetchers, world, params); + let invokation = tokenData.invokation; + delete tokenData.invokation; + + if (invokation.error) { + throw invokation.error; + } + + const cToken = invokation.value!; + tokenData.address = cToken._address; + + world = await storeAndSaveContract( + world, + cToken, + tokenData.symbol, + invokation, + [ + { index: ['cTokens', tokenData.symbol], data: tokenData }, + { index: ['Tokens', tokenData.symbol], data: tokenData } + ] + ); + + return {world, cToken, tokenData}; +} diff --git a/scenario/src/Builder/ComptrollerImplBuilder.ts b/scenario/src/Builder/ComptrollerImplBuilder.ts new file mode 100644 index 000000000..33e04c6a5 --- /dev/null +++ b/scenario/src/Builder/ComptrollerImplBuilder.ts @@ -0,0 +1,175 @@ +import {Event} from '../Event'; +import {addAction, World} from '../World'; +import {ComptrollerImpl} from '../Contract/ComptrollerImpl'; +import {Invokation, invoke} from '../Invokation'; +import { + getAddressV, + getExpNumberV, + getNumberV, + getStringV +} from '../CoreValue'; +import { + AddressV, + NothingV, + NumberV, + StringV +} from '../Value'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {storeAndSaveContract} from '../Networks'; +import {getContract, getTestContract} from '../Contract'; + +const ComptrollerContract = getContract("Comptroller"); +const ComptrollerScenarioContract = getTestContract('ComptrollerScenario'); +const ComptrollerBorkedContract = getTestContract('ComptrollerBorked'); +const ComptrollerBoolContract = getTestContract('BoolComptroller'); + +export interface ComptrollerImplData { + invokation: Invokation + name: string + contract: string + description: string +} + +export async function buildComptrollerImpl(world: World, from: string, event: Event): Promise<{world: World, comptrollerImpl: ComptrollerImpl, comptrollerImplData: ComptrollerImplData}> { + const fetchers = [ + new Fetcher<{name: StringV | NothingV}, ComptrollerImplData>(` + #### Scenario + + * "Scenario name:" - The Comptroller Scenario for local testing + * E.g. "ComptrollerImpl Deploy Scenario MyScen" + `, + "Scenario", + [ + new Arg("name", getStringV, {nullable: true}), + ], + async (world, {name}) => ({ + invokation: await ComptrollerScenarioContract.deploy(world, from, []), + name: name instanceof StringV ? name.val : "Comptroller", + contract: "ComptrollerScenario", + description: "Scenario Comptroller Impl" + }) + ), + new Fetcher<{name: StringV | NothingV}, ComptrollerImplData>(` + #### Standard + + * "Standard name:" - The standard Comptroller contract + * E.g. "Comptroller Deploy Standard MyStandard" + `, + "Standard", + [ + new Arg("name", getStringV, {nullable: true}) + ], + async (world, {name}) => { + let invokation; + let contract; + + return { + invokation: await ComptrollerContract.deploy(world, from, []), + name: name instanceof StringV ? name.val : "Comptroller", + contract: "Comptroller", + description: "Standard Comptroller Impl" + }; + }, + ), + new Fetcher<{name: StringV | NothingV}, ComptrollerImplData>(` + #### YesNo + + * "YesNo name:" - The bool Comptroller contract + * E.g. "Comptroller Deploy YesNo MyBool" + `, + "YesNo", + [ + new Arg("name", getStringV, {nullable: true}) + ], + async (world, {name}) => { + let invokation; + let contract; + + return { + invokation: await ComptrollerBoolContract.deploy(world, from, []), + name: name instanceof StringV ? name.val : "Comptroller", + contract: "Comptroller", + description: "YesNo Comptroller" + }; + }, + ), + new Fetcher<{name: StringV | NothingV}, ComptrollerImplData>(` + #### Borked + + * "Borked name:" - A Borked Comptroller for testing + * E.g. "ComptrollerImpl Deploy Borked MyBork" + `, + "Borked", + [ + new Arg("name", getStringV, {nullable: true}) + ], + async (world, {name}) => ({ + invokation: await ComptrollerBorkedContract.deploy(world, from, []), + name: name instanceof StringV ? name.val : "Comptroller", + contract: "ComptrollerBorked", + description: "Borked Comptroller Impl" + }) + ), + new Fetcher<{name: StringV | NothingV}, ComptrollerImplData>(` + #### Default + + * "name:" - The standard Comptroller contract + * E.g. "ComptrollerImpl Deploy MyDefault" + `, + "Default", + [ + new Arg("name", getStringV, {nullable: true}) + ], + async (world, {name}) => { + let invokation; + let contract; + + if (world.isLocalNetwork()) { + // Note: we're going to use the scenario contract as the standard deployment on local networks + return { + invokation: await ComptrollerScenarioContract.deploy(world, from, []), + name: name instanceof StringV ? name.val : "Comptroller", + contract: "ComptrollerScenario", + description: "Scenario Comptroller Impl" + }; + } else { + return { + invokation: await ComptrollerContract.deploy(world, from, []), + name: name instanceof StringV ? name.val : "Comptroller", + contract: "Comptroller", + description: "Standard Comptroller Impl" + }; + } + }, + {catchall: true} + ) + ]; + + let comptrollerImplData = await getFetcherValue("DeployComptrollerImpl", fetchers, world, event); + let invokation = comptrollerImplData.invokation; + delete comptrollerImplData.invokation; + + if (invokation.error) { + throw invokation.error; + } + const comptrollerImpl = invokation.value!; + + world = await storeAndSaveContract( + world, + comptrollerImpl, + comptrollerImplData.name, + invokation, + [ + { + index: ['Comptroller', comptrollerImplData.name], + data: { + address: comptrollerImpl._address, + contract: comptrollerImplData.contract, + description: comptrollerImplData.description + } + } + ] + ); + + return {world, comptrollerImpl, comptrollerImplData}; +} diff --git a/scenario/src/Builder/Erc20Builder.ts b/scenario/src/Builder/Erc20Builder.ts new file mode 100644 index 000000000..8e76791e8 --- /dev/null +++ b/scenario/src/Builder/Erc20Builder.ts @@ -0,0 +1,185 @@ +import {Event} from '../Event'; +import {addAction, World} from '../World'; +import {Erc20} from '../Contract/Erc20'; +import {Invokation, invoke} from '../Invokation'; +import { + getAddressV, + getCoreValue, + getNumberV, + getStringV +} from '../CoreValue'; +import { + AddressV, + NumberV, + StringV, + Value +} from '../Value'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {storeAndSaveContract} from '../Networks'; +import {getContract, getTestContract} from '../Contract'; +import {encodeABI} from '../Utils'; + +const FaucetTokenHarness = getContract("FaucetToken"); +const FaucetTokenNonStandardHarness = getContract("FaucetNonStandardToken"); +const FaucetTokenReEntrantHarness = getContract("FaucetTokenReEntrantHarness"); +const EvilTokenHarness = getContract("EvilToken"); +const WBTCTokenHarness = getContract("WBTCToken"); + +export interface TokenData { + invokation: Invokation, + description: string, + name: string, + symbol: string, + decimals: number, + address?: string, + contract: string +} + +export async function buildErc20(world: World, from: string, event: Event): Promise<{world: World, erc20: Erc20, tokenData: TokenData}> { + const fetchers = [ + new Fetcher<{symbol: StringV, name: StringV, decimals: NumberV}, TokenData>(` + #### NonStandard + + * "NonStandard symbol: name: decimals:" - A non-standard token, like BAT + * E.g. "Erc20 Deploy NonStandard BAT 18" + `, + "NonStandard", + [ + new Arg("symbol", getStringV), + new Arg("name", getStringV), + new Arg("decimals", getNumberV, {default: new NumberV(18)}), + ], + async (world, {symbol, name, decimals}) => { + return { + invokation: await FaucetTokenNonStandardHarness.deploy(world, from, [0, name.val, decimals.val, symbol.val]), + description: "NonStandard", + name: name.val, + symbol: symbol.val, + decimals: decimals.toNumber(), + contract: 'FaucetNonStandardToken' + }; + } + ), + new Fetcher<{symbol: StringV, name: StringV, fun:StringV, reEntryFunSig: StringV, reEntryFunArgs: StringV[]}, TokenData>(` + #### ReEntrant + + * "ReEntrant symbol: name:string fun: funSig: ...funArgs:" - A token that loves to call back to spook its caller + * E.g. "Erc20 Deploy ReEntrant PHREAK PHREAK "transfer" "mint(uint256)" 0 - A token that will call back to a CToken's mint function + + Note: valid functions: totalSupply, balanceOf, transfer, transferFrom, approve, allowance + `, + "ReEntrant", + [ + new Arg("symbol", getStringV), + new Arg("name", getStringV), + new Arg("fun", getStringV), + new Arg("reEntryFunSig", getStringV), + new Arg("reEntryFunArgs", getStringV, {variadic: true, mapped: true}) + ], + async (world, {symbol, name, fun, reEntryFunSig, reEntryFunArgs}) => { + const fnData = encodeABI(world, reEntryFunSig.val, reEntryFunArgs.map((a) => a.val)); + + return { + invokation: await FaucetTokenReEntrantHarness.deploy(world, from, [0, name.val, 18, symbol.val, fnData, fun.val]), + description: "ReEntrant", + name: name.val, + symbol: symbol.val, + decimals: 18, + contract: 'FaucetTokenReEntrantHarness' + }; + } + ), + new Fetcher<{symbol: StringV, name: StringV, decimals: NumberV}, TokenData>(` + #### Evil + + * "Evil symbol: name: decimals:" - A less vanilla ERC-20 contract that fails transfers + * E.g. "Erc20 Deploy Evil BAT 18" + `, + "Evil", + [ + new Arg("symbol", getStringV), + new Arg("name", getStringV), + new Arg("decimals", getNumberV, {default: new NumberV(18)}) + ], + async (world, {symbol, name, decimals}) => { + return { + invokation: await EvilTokenHarness.deploy(world, from, [0, name.val, decimals.val, symbol.val]), + description: "Evil", + name: name.val, + symbol: symbol.val, + decimals: decimals.toNumber(), + contract: 'EvilToken' + }; + } + ), + new Fetcher<{symbol: StringV, name: StringV, decimals: NumberV}, TokenData>(` + #### Standard + + * "Standard symbol: name: decimals:" - A vanilla ERC-20 contract + * E.g. "Erc20 Deploy Standard BAT 18" + `, + "Standard", + [ + new Arg("symbol", getStringV), + new Arg("name", getStringV), + new Arg("decimals", getNumberV, {default: new NumberV(18)}) + ], + async (world, {symbol, name, decimals}) => { + return { + invokation: await FaucetTokenHarness.deploy(world, from, [0, name.val, decimals.val, symbol.val]), + description: "Standard", + name: name.val, + symbol: symbol.val, + decimals: decimals.toNumber(), + contract: 'FaucetToken' + }; + } + ), + new Fetcher<{symbol: StringV, name: StringV}, TokenData>(` + #### WBTC + + * "WBTC symbol: name:" - The WBTC contract + * E.g. "Erc20 Deploy WBTC WBTC \"Wrapped Bitcoin\"" + `, + "WBTC", + [ + new Arg("symbol", getStringV, {default: new StringV("WBTC")}), + new Arg("name", getStringV, {default: new StringV("Wrapped Bitcoin")}) + ], + async (world, {symbol, name}) => { + let decimals = 8; + + return { + invokation: await WBTCTokenHarness.deploy(world, from, []), + description: "WBTC", + name: name.val, + symbol: symbol.val, + decimals: decimals, + contract: 'WBTCToken' + }; + } + ) + ]; + + let tokenData = await getFetcherValue("DeployErc20", fetchers, world, event); + let invokation = tokenData.invokation; + delete tokenData.invokation; + + if (invokation.error) { + throw invokation.error; + } + const erc20 = invokation.value!; + tokenData.address = erc20._address; + + world = await storeAndSaveContract( + world, + erc20, + tokenData.symbol, + invokation, + [ + { index: ['Tokens', tokenData.symbol], data: tokenData } + ] + ); + + return {world, erc20, tokenData}; +} diff --git a/scenario/src/Builder/InterestRateModelBuilder.ts b/scenario/src/Builder/InterestRateModelBuilder.ts new file mode 100644 index 000000000..29280451f --- /dev/null +++ b/scenario/src/Builder/InterestRateModelBuilder.ts @@ -0,0 +1,100 @@ +import {Event} from '../Event'; +import {addAction, World} from '../World'; +import {InterestRateModel} from '../Contract/InterestRateModel'; +import {Invokation, invoke} from '../Invokation'; +import { + getExpNumberV, + getPercentV, + getStringV, +} from '../CoreValue'; +import { + EventV, + NumberV, + StringV, +} from '../Value'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {storeAndSaveContract} from '../Networks'; +import {getContract, getTestContract} from '../Contract'; + +const FixedInterestRateModel = getTestContract('InterestRateModelHarness'); +const WhitePaperInterestRateModel = getContract('WhitePaperInterestRateModel'); + +export interface InterestRateModelData { + invokation: Invokation + address?: string + name: string + contract: string + description: string + base?: string + slope?: string +} + +export async function buildInterestRateModel(world: World, from: string, event: Event): Promise<{world: World, interestRateModel: InterestRateModel, interestRateModelData: InterestRateModelData}> { + const fetchers = [ + new Fetcher<{name: StringV, rate: NumberV}, InterestRateModelData>(` + #### Fixed + + * "Fixed name: rate:" - Fixed interest **per-block** rate + * E.g. "InterestRateModel Deploy Fixed MyInterestRateModel 0.5" + `, + "Fixed", + [ + new Arg("name", getStringV), + new Arg("rate", getPercentV), + ], + async (world, {name, rate}) => ({ + invokation: await FixedInterestRateModel.deploy(world, from, [rate.val]), + name: name.val, + contract: "InterestRateModelHarness", + description: `Fixed rate ${rate.show()} per block` + }) + ), + + new Fetcher<{name: StringV, baseRate: NumberV, multiplier: NumberV}, InterestRateModelData>(` + #### WhitePaper + + * "WhitePaper name: baseRate: multiplier:" - The WhitePaper interest rate + * E.g. "InterestRateModel Deploy WhitePaper MyInterestRateModel 0.05 0.2" - 5% base rate and 20% utilization multiplier + `, + "WhitePaper", + [ + new Arg("name", getStringV), + new Arg("baseRate", getExpNumberV), + new Arg("multiplier", getExpNumberV) + ], + async (world, {name, baseRate, multiplier}) => ({ + invokation: await WhitePaperInterestRateModel.deploy(world, from, [baseRate.val, multiplier.val]), + name: name.val, + contract: "WhitePaperInterestRateModel", + description: `WhitePaper baseRate=${baseRate.val} multiplier=${multiplier.val}`, + base: baseRate.encode().toString(), + slope: multiplier.encode().toString() + }) + ) + ]; + + let interestRateModelData = await getFetcherValue("DeployInterestRateModel", fetchers, world, event); + let invokation = interestRateModelData.invokation; + delete interestRateModelData.invokation; + + if (invokation.error) { + throw invokation.error; + } + const interestRateModel = invokation.value!; + interestRateModelData.address = interestRateModel._address; + + world = await storeAndSaveContract( + world, + interestRateModel, + interestRateModelData.name, + invokation, + [ + { + index: ['InterestRateModel', interestRateModelData.name], + data: interestRateModelData + } + ] + ); + + return {world, interestRateModel, interestRateModelData}; +} diff --git a/scenario/src/Builder/MaximillionBuilder.ts b/scenario/src/Builder/MaximillionBuilder.ts new file mode 100644 index 000000000..c8eb81a03 --- /dev/null +++ b/scenario/src/Builder/MaximillionBuilder.ts @@ -0,0 +1,64 @@ +import {Event} from '../Event'; +import {addAction, World} from '../World'; +import {Maximillion} from '../Contract/Maximillion'; +import {Invokation} from '../Invokation'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {storeAndSaveContract} from '../Networks'; +import {getContract} from '../Contract'; +import {getAddressV} from '../CoreValue'; +import {AddressV} from '../Value'; + +const MaximillionContract = getContract("Maximillion"); + +export interface MaximillionData { + invokation: Invokation, + description: string, + cEtherAddress: string, + address?: string +} + +export async function buildMaximillion(world: World, from: string, event: Event): Promise<{world: World, maximillion: Maximillion, maximillionData: MaximillionData}> { + const fetchers = [ + new Fetcher<{cEther: AddressV}, MaximillionData>(` + #### Maximillion + + * "" - Maximum Eth Repays Contract + * E.g. "Maximillion Deploy" + `, + "Maximillion", + [ + new Arg("cEther", getAddressV) + ], + async (world, {cEther}) => { + return { + invokation: await MaximillionContract.deploy(world, from, [cEther.val]), + description: "Maximillion", + cEtherAddress: cEther.val + }; + }, + {catchall: true} + ) + ]; + + let maximillionData = await getFetcherValue("DeployMaximillion", fetchers, world, event); + let invokation = maximillionData.invokation; + delete maximillionData.invokation; + + if (invokation.error) { + throw invokation.error; + } + const maximillion = invokation.value!; + maximillionData.address = maximillion._address; + + world = await storeAndSaveContract( + world, + maximillion, + 'Maximillion', + invokation, + [ + { index: ['Maximillion'], data: maximillionData } + ] + ); + + return {world, maximillion, maximillionData}; +} diff --git a/scenario/src/Builder/PriceOracleBuilder.ts b/scenario/src/Builder/PriceOracleBuilder.ts new file mode 100644 index 000000000..5888bd623 --- /dev/null +++ b/scenario/src/Builder/PriceOracleBuilder.ts @@ -0,0 +1,165 @@ +import {Event} from '../Event'; +import {addAction, World} from '../World'; +import {PriceOracle} from '../Contract/PriceOracle'; +import {Invokation, invoke} from '../Invokation'; +import { + getAddressV, + getExpNumberV, + getStringV +} from '../CoreValue'; +import { + AddressV, + EventV, + NothingV, + NumberV, + StringV +} from '../Value'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {storeAndSaveContract} from '../Networks'; +import {getContract, getTestContract} from '../Contract'; + +const FixedPriceOracle = getTestContract('FixedPriceOracle'); +const SimplePriceOracle = getContract('SimplePriceOracle'); +const AnchorPriceOracle = getContract('AnchorPriceOracle'); +const NotPriceOracle = getTestContract('NotPriceOracle'); +const PriceOracleInterface = getTestContract('PriceOracle'); + +export interface PriceOracleData { + invokation?: Invokation, + contract?: PriceOracle, + description: string, + address?: string +} + +export async function buildPriceOracle(world: World, from: string, event: Event): Promise<{world: World, priceOracle: PriceOracle, priceOracleData: PriceOracleData}> { + const fetchers = [ + new Fetcher<{price: NumberV}, PriceOracleData>(` + #### Fixed + + * "Fixed price:" - Fixed price + * E.g. "PriceOracle Deploy (Fixed 20.0)" + `, + "Fixed", + [ + new Arg("price", getExpNumberV), + ], + async (world, {price}) => { + return { + invokation: await FixedPriceOracle.deploy(world, from, [price.val]), + description: "Fixed Price Oracle" + }; + } + ), + new Fetcher<{}, PriceOracleData>(` + #### Simple + + * "Simple" - The a simple price oracle that has a harness price setter + * E.g. "PriceOracle Deploy Simple" + `, + "Simple", + [], + async (world, {}) => { + return { + invokation: await SimplePriceOracle.deploy(world, from, []), + description: "Simple Price Oracle" + }; + } + ), + new Fetcher<{poster: AddressV}, PriceOracleData>(` + #### Anchor + + * "Anchor " - The anchor price oracle that caps price movements to anchors + * E.g. "PriceOracle Deploy Anchor 0x..." + `, + "Anchor", + [ + new Arg("poster", getAddressV) + ], + async (world, {poster}) => { + return { + invokation: await AnchorPriceOracle.deploy(world, from, [poster.val]), + description: "Anchor Price Oracle", + poster: poster.val + }; + } + ), + new Fetcher<{}, PriceOracleData>(` + #### NotPriceOracle + + * "NotPriceOracle" - Not actually a price oracle + * E.g. "PriceOracle Deploy NotPriceOracle" + `, + "NotPriceOracle", + [], + async (world, {}) => { + return { + invokation: await NotPriceOracle.deploy(world, from, []), + description: "Not a Price Oracle" + }; + } + ) + ]; + + let priceOracleData = await getFetcherValue("DeployPriceOracle", fetchers, world, event); + let invokation = priceOracleData.invokation!; + delete priceOracleData.invokation; + + if (invokation.error) { + throw invokation.error; + } + const priceOracle = invokation.value!; + priceOracleData.address = priceOracle._address; + + world = await storeAndSaveContract( + world, + priceOracle, + 'PriceOracle', + invokation, + [ + { index: ['PriceOracle'], data: priceOracleData } + ] + ); + + return {world, priceOracle, priceOracleData}; +} + +export async function setPriceOracle(world: World, event: Event): Promise<{world: World, priceOracle: PriceOracle, priceOracleData: PriceOracleData}> { + const fetchers = [ + new Fetcher<{address: AddressV, description: StringV}, PriceOracleData>(` + #### Standard + + * "Standard" - The standard price oracle + * E.g. "PriceOracle Set Standard \"0x...\" \"Standard Price Oracle\"" + `, + "Standard", + [ + new Arg("address", getAddressV), + new Arg("description", getStringV), + ], + async (world, {address, description}) => { + return { + contract: await PriceOracleInterface.at(world, address.val), + description: description.val + }; + } + ) + ]; + + let priceOracleData = await getFetcherValue("SetPriceOracle", fetchers, world, event); + let priceOracle = priceOracleData.contract!; + delete priceOracleData.contract; + + priceOracleData.address = priceOracle._address; + + world = await storeAndSaveContract( + world, + priceOracle, + 'PriceOracle', + null, + [ + { index: ['PriceOracle'], data: priceOracleData } + ] + ); + + return {world, priceOracle, priceOracleData}; +} diff --git a/scenario/src/Builder/PriceOracleProxyBuilder.ts b/scenario/src/Builder/PriceOracleProxyBuilder.ts new file mode 100644 index 000000000..4b3033429 --- /dev/null +++ b/scenario/src/Builder/PriceOracleProxyBuilder.ts @@ -0,0 +1,70 @@ +import {Event} from '../Event'; +import {addAction, World} from '../World'; +import {PriceOracleProxy} from '../Contract/PriceOracleProxy'; +import {Invokation} from '../Invokation'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {storeAndSaveContract} from '../Networks'; +import {getContract} from '../Contract'; +import {getAddressV} from '../CoreValue'; +import {AddressV} from '../Value'; + +const PriceOracleProxyContract = getContract("PriceOracleProxy"); + +export interface PriceOracleProxyData { + invokation?: Invokation, + contract?: PriceOracleProxy, + description: string, + address?: string, + cEther: string, + cUSDC: string, +} + +export async function buildPriceOracleProxy(world: World, from: string, event: Event): Promise<{world: World, priceOracleProxy: PriceOracleProxy, invokation: Invokation}> { + const fetchers = [ + new Fetcher<{comptroller: AddressV, priceOracle: AddressV, cEther: AddressV, cUSDC: AddressV}, PriceOracleProxyData>(` + #### Price Oracle Proxy + + * "Deploy " - The Price Oracle which proxies to a backing oracle + * E.g. "PriceOracleProxy Deploy (Unitroller Address) (PriceOracle Address) cETH cUSDC" + `, + "PriceOracleProxy", + [ + new Arg("comptroller", getAddressV), + new Arg("priceOracle", getAddressV), + new Arg("cEther", getAddressV), + new Arg("cUSDC", getAddressV) + ], + async (world, {comptroller, priceOracle, cEther, cUSDC}) => { + return { + invokation: await PriceOracleProxyContract.deploy(world, from, [comptroller.val, priceOracle.val, cEther.val, cUSDC.val]), + description: "Price Oracle Proxy", + cEther: cEther.val, + cUSDC: cUSDC.val + }; + }, + {catchall: true} + ) + ]; + + let priceOracleProxyData = await getFetcherValue("DeployPriceOracleProxy", fetchers, world, event); + let invokation = priceOracleProxyData.invokation!; + delete priceOracleProxyData.invokation; + + if (invokation.error) { + throw invokation.error; + } + const priceOracleProxy = invokation.value!; + priceOracleProxyData.address = priceOracleProxy._address; + + world = await storeAndSaveContract( + world, + priceOracleProxy, + 'PriceOracleProxy', + invokation, + [ + { index: ['PriceOracleProxy'], data: priceOracleProxyData } + ] + ); + + return {world, priceOracleProxy, invokation}; +} diff --git a/scenario/src/Builder/UnitrollerBuilder.ts b/scenario/src/Builder/UnitrollerBuilder.ts new file mode 100644 index 000000000..d934dec9f --- /dev/null +++ b/scenario/src/Builder/UnitrollerBuilder.ts @@ -0,0 +1,58 @@ +import {Event} from '../Event'; +import {addAction, World} from '../World'; +import {Unitroller} from '../Contract/Unitroller'; +import {Invokation} from '../Invokation'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {storeAndSaveContract} from '../Networks'; +import {getContract} from '../Contract'; + +const UnitrollerContract = getContract("Unitroller"); + +export interface UnitrollerData { + invokation: Invokation, + description: string, + address?: string +} + +export async function buildUnitroller(world: World, from: string, event: Event): Promise<{world: World, unitroller: Unitroller, unitrollerData: UnitrollerData}> { + const fetchers = [ + new Fetcher<{}, UnitrollerData>(` + #### Unitroller + + * "" - The Upgradable Comptroller + * E.g. "Unitroller Deploy" + `, + "Unitroller", + [], + async (world, {}) => { + return { + invokation: await UnitrollerContract.deploy(world, from, []), + description: "Unitroller" + }; + }, + {catchall: true} + ) + ]; + + let unitrollerData = await getFetcherValue("DeployUnitroller", fetchers, world, event); + let invokation = unitrollerData.invokation; + delete unitrollerData.invokation; + + if (invokation.error) { + throw invokation.error; + } + const unitroller = invokation.value!; + unitrollerData.address = unitroller._address; + + world = await storeAndSaveContract( + world, + unitroller, + 'Unitroller', + invokation, + [ + { index: ['Unitroller'], data: unitrollerData } + ] + ); + + return {world, unitroller, unitrollerData}; +} diff --git a/scenario/src/Command.ts b/scenario/src/Command.ts new file mode 100644 index 000000000..596e05f2c --- /dev/null +++ b/scenario/src/Command.ts @@ -0,0 +1,248 @@ +import {Event} from './Event'; +import {World} from './World'; +import {mustArray} from './Utils'; +import {NothingV} from './Value'; + +interface ArgOpts { + default?: T + implicit?: boolean + variadic?: boolean + mapped?: boolean + nullable?: boolean + rescue?: T +} + +export class Arg { + name: string + type: any + getter: (World, Event?) => Promise + defaultValue: T | undefined + implicit: boolean + variadic: boolean + mapped: boolean + nullable: boolean + rescue: T | undefined + + constructor(name: string, getter: (World, Event?) => Promise, opts = >{}) { + this.name = name; + this.getter = getter; + this.defaultValue = opts.default; + this.implicit = !!opts.implicit; + this.variadic = !!opts.variadic; + this.mapped = !!opts.mapped; + this.nullable = !!opts.nullable; + this.rescue = opts.rescue; + } +} + +interface ExpressionOpts { + namePos?: number + catchall?: boolean + subExpressions?: Expression[] +} + +export abstract class Expression { + doc: string + name: string + args: Arg[] + namePos: number + catchall: boolean + subExpressions: Expression[] + + constructor(doc: string, name: string, args: Arg[], opts: ExpressionOpts={}) { + this.doc = Command.cleanDoc(doc); + this.name = name; + this.args = args; + this.namePos = opts.namePos || 0; + this.catchall = opts.catchall || false; + this.subExpressions = opts.subExpressions || []; + } + + getNameArgs(event: Event): [string | null, Event] { + // Unwrap double-wrapped expressions e.g. [[Exactly, "1.0"]] -> ["Exactly", "1.0"] + if (Array.isArray(event) && event.length === 1 && Array.isArray(event[0])) { + const [eventInner] = event; + + return this.getNameArgs(eventInner); + } + + // Let's allow single-length complex expressions to be passed without parens e.g. "True" -> ["True"] + if (!Array.isArray(event)) { + event = [event]; + } + + if (this.catchall) { + return [this.name, event]; + } else { + let args = event.slice(); + let [name] = args.splice(this.namePos, 1); + + if (Array.isArray(name)) { + return [null, event]; + } + + return [name, args]; + } + } + + matches(event: Event): boolean { + if (this.catchall) { + return true; + } + + const [name, _args] = this.getNameArgs(event); + + return !!name && name.toLowerCase().trim() === this.name.toLowerCase().trim(); + } + + async getArgs(world: World, event: Event): Promise { + const [_name, eventArgs] = this.getNameArgs(event); + + let initialAcc = <{currArgs: Args, currEvents: Event}>{currArgs: {}, currEvents: eventArgs}; + + const {currArgs: args, currEvents: restEvent} = await this.args.reduce(async (acc, arg) => { + let {currArgs, currEvents} = await acc; + let val: any; + let restEventArgs: Event; + + if (arg.nullable && currEvents.length === 0) { // Note this is zero-length string or zero-length array + val = new NothingV(); + restEventArgs = currEvents; + } else if (arg.variadic) { + if (arg.mapped) { + // If mapped, mapped the function over each event arg + val = await Promise.all(currEvents.map((event) => arg.getter(world, event))); + } else { + val = await arg.getter(world, currEvents); + } + restEventArgs = []; + } else if (arg.implicit) { + val = await arg.getter(world); + restEventArgs = currEvents; + } else { + let eventArg; + + [eventArg, ...restEventArgs] = currEvents; + + if (eventArg === undefined) { + if (arg.defaultValue) { + val = arg.defaultValue; + } else { + throw new Error(`Missing argument ${arg.name} when processing ${this.name}`); + } + } else { + try { + if (arg.mapped) { + val = await await Promise.all(mustArray(eventArg).map((el) => arg.getter(world, el))); + } else { + val = await arg.getter(world, eventArg); + } + } catch (err) { + if (arg.rescue) { + // Rescue is meant to allow Gate to work for checks that + // fail due to the missing components, e.g.: + // `Gate (CToken Eth Address) (... deploy cToken)` + // could be used to deploy a cToken if it doesn't exist, but + // since there is no CToken, that check would raise (when we'd + // hope it just returns null). So here, we allow our code to rescue + // errors and recover, but we need to be smarter about catching specific + // errors instead of all errors. For now, to assist debugging, we may print + // any error that comes up, even if it was intended. + // world.printer.printError(err); + + val = arg.rescue; + } else { + throw err; + } + } + } + } + + let newArgs = { + ...currArgs, + [arg.name]: val + }; + + return { + currArgs: newArgs, + currEvents: restEventArgs + }; + }, Promise.resolve(initialAcc)); + + if (restEvent.length !== 0) { + throw new Error(`Found extra args: ${restEvent.toString()} when processing ${this.name}`); + } + + return args; + } + + static cleanDoc(doc: string): string { + return doc.replace(/^\s+/mg, '').replace(/"/g, '`'); + } +} + +export class Command extends Expression { + processor: (world: World, from: string, args: Args) => Promise + requireFrom: boolean = true; + + constructor(doc: string, name: string, args: Arg[], processor: (world: World, from: string, args: Args) => Promise, opts: ExpressionOpts={}) { + super(doc, name, args, opts); + + this.processor = processor; + } + + async process(world: World, from: string | null, event: Event): Promise { + let args = await this.getArgs(world, event); + if (this.requireFrom) { + if (!from) { + throw new Error(`From required but not given for ${this.name}. Please set a default alias or open unlocked account`); + } + + return await this.processor(world, from, args); + } else { + return await this.processor(world, null, args); + } + } +} + +export class View extends Command { + constructor(doc: string, name: string, args: Arg[], processor: (world: World, args: Args) => Promise, opts: ExpressionOpts={}) { + super(doc, name, args, (world, from, args) => processor(world, args), opts); + this.requireFrom = false; + } +} + +export class Fetcher extends Expression { + fetcher: (world: World, args: Args) => Promise + + constructor(doc: string, name: string, args: Arg[], fetcher: (world: World, args: Args) => Promise, opts: ExpressionOpts={}) { + super(doc, name, args, opts); + + this.fetcher = fetcher; + } + + async fetch(world: World, event: Event): Promise { + let args = await this.getArgs(world, event); + return await this.fetcher(world, args); + } +} + +export async function processCommandEvent(type: string, commands: Command[], world: World, event: Event, from: string | null): Promise { + let matchingCommand = commands.find((command) => command.matches(event)); + + if (!matchingCommand) { + throw new Error(`Found unknown ${type} event type ${event.toString()}`); + } + + return matchingCommand.process(world, from, event); +} + +export async function getFetcherValue(type: string, fetchers: Fetcher[], world: World, event: Event): Promise { + let matchingFetcher = fetchers.find((fetcher) => fetcher.matches(event)); + + if (!matchingFetcher) { + throw new Error(`Found unknown ${type} value type ${JSON.stringify(event)}`); + } + + return matchingFetcher.fetch(world, event); +} diff --git a/scenario/src/Completer.ts b/scenario/src/Completer.ts new file mode 100644 index 000000000..35f90782b --- /dev/null +++ b/scenario/src/Completer.ts @@ -0,0 +1,36 @@ +import {World} from './World'; +import {Macros} from './Macro'; + +// TODO: Get smarter about storing actions as data +const actions: string[] = [ + "Read", + "Assert", + "FastForward", + "Inspect", + "Debug", + "From", + "Invariant", + "Comptroller", + "cToken", + "Erc20", +]; + +function caseInsensitiveSort(a: string, b: string): number { + let A = a.toUpperCase(); + let B = b.toUpperCase(); + + if (A < B) { + return -1; + } else if (A > B) { + return 1; + } else { + return 0; + } +} + +export function complete(world: World, macros: Macros, line: string) { + let allActions = actions.concat(Object.keys(macros)).sort(caseInsensitiveSort); + const hits = allActions.filter((c) => c.toLowerCase().startsWith(line.toLowerCase())); + + return [hits, line]; +} diff --git a/scenario/src/Contract.ts b/scenario/src/Contract.ts new file mode 100644 index 000000000..7581937b1 --- /dev/null +++ b/scenario/src/Contract.ts @@ -0,0 +1,221 @@ +import * as path from 'path'; +import * as crypto from 'crypto'; +import {World} from './World'; +import {Artifact} from './Artifact'; +import {Invokation} from './Invokation'; +import {ErrorReporter, NoErrorReporter} from './ErrorReporter'; +import {getNetworkPath, readFile} from './File'; + +export interface ABIInput { + name: string + type: string +} + +export interface ABIOutput { + name: string + type: string +} + +export interface ABI { + type: string + name: string + constant: boolean + payable: boolean + stateMutability: string + inputs: ABIInput[] + outputs: ABIOutput[] +} + +export interface Raw { + data: string + topics: string[] +} + +export interface Event { + event: string + signature: string | null + address: string + returnValues: object + logIndex: number + transactionIndex: number + blockHash: string + blockNumber: number + raw: Raw +} + +export interface Contract { + _address: string + name: string + methods: any + _jsonInterface: ABI[] + constructorAbi?: string + getPastEvents: (event: string, options: { filter: object, fromBlock: number, toBlock: number | string }) => Event[] +} + +function randomAddress(): string { + return crypto.randomBytes(20).toString('hex'); +} + +class ContractStub { + name: string; + cache: Artifact | null; + test: boolean + + constructor(name: string, test: boolean) { + this.name = name; + this.cache = null; + this.test = test; + } + + async deploy(world: World, from: string, args: any[]): Promise> { + const opts = world.web3.currentProvider.opts || {}; + opts.from = from; + + let {networkContracts} = await getNetworkContracts(world); + let networkContract = networkContracts[this.name]; + if (!networkContract) { + throw new Error(`Cannot find contract ${this.name}, found: ${Object.keys(networkContracts)}`) + } + + let invokationOpts = world.getInvokationOpts(opts); + + let contractAbi = JSON.parse(networkContract.abi); + const contract = new world.web3.eth.Contract(contractAbi, null, opts); + const constructorAbi = contractAbi.find((x) => x.type === 'constructor'); + let inputs; + + if (constructorAbi) { + inputs = constructorAbi.inputs; + } else { + inputs = []; + } + + const abi = world.web3.eth.abi.encodeParameters(inputs, args); + + try { + let deployed; + let deployReceipt; + + if (world.dryRun) { + let addr = randomAddress(); + console.log(`Dry run: Deploying ${this.name} at fake address ${addr}`); + deployed = { + ...contract, + _address: addr + }; + deployed.options.address = addr; + deployReceipt = { + blockNumber: -1, + transactionHash: "0x", + events: {} + }; + } else { + deployed = await (contract.deploy({data: '0x' + networkContract.bin, arguments: args}).send(invokationOpts).on('receipt', (receipt) => (deployReceipt = receipt))); + deployed.constructorAbi = abi; + } + + return new Invokation(deployed, deployReceipt, null, null); + } catch (err) { + return new Invokation(null, null, err, null); + } + } + + at(world: World, address: string): T { + let artifact; + + if (!world.artifacts) { + throw new Error(`Cannot deploy contracts with missing artifacts`); + } + + if (this.cache) { + artifact = this.cache; + } else { + artifact = world.artifacts.require(this.name); + this.cache = artifact; + } + + return new world.web3.eth.Contract(artifact._json.abi, address); + } +} + +export function getContract(name: string): ContractStub { + return new ContractStub(name, false); +} + +export function getTestContract(name: string): ContractStub { + return new ContractStub(name, true); +} + +export function setContractName(name: string, contract: Contract): Contract { + contract.name = name; + + return contract; +} + +export async function getPastEvents(world: World, contract: Contract, name: string, event: string, filter: object={}): Promise { + const block = world.getIn(['contractData', 'Blocks', name]); + if (!block) { + throw new Error(`Cannot get events when missing deploy block for ${name}`); + } + + return await contract.getPastEvents(event, { filter: filter, fromBlock: block, toBlock: 'latest' }); +} + +export async function decodeCall(world: World, contract: Contract, input: string): Promise { + if (input.slice(0, 2) === '0x') { + input = input.slice(2); + } + + let functionSignature = input.slice(0, 8); + let argsEncoded = input.slice(8); + + let funsMapped = contract._jsonInterface.reduce((acc, fun) => { + if (fun.type === 'function') { + let functionAbi = `${fun.name}(${fun.inputs.map((i) => i.type).join(',')})`; + let sig = world.web3.utils.sha3(functionAbi).slice(2, 10); + + return { + ...acc, + [sig]: fun + }; + } else { + return acc; + } + }, {}); + + let abi = funsMapped[functionSignature]; + + if (!abi) { + throw new Error(`Cannot find function matching signature ${functionSignature}`); + } + + let decoded = world.web3.eth.abi.decodeParameters(abi.inputs, argsEncoded); + + const args = abi.inputs.map((input) => { + return `${input.name}=${decoded[input.name]}`; + }); + world.printer.printLine(`\n${contract.name}.${abi.name}(\n\t${args.join("\n\t")}\n)`); + + return world; +} + +export async function getNetworkContracts(world: World): Promise<{networkContracts: object, version: string}> { + let fullContracts = await readFile(getNetworkPath(world.basePath, world.network, '-contracts', 'json'), null, JSON.parse); + let version = fullContracts.version; + let networkContracts = Object.entries(fullContracts.contracts).reduce((acc, [k, v]) => { + let [path, contractName] = k.split(':'); + + return { + ...acc, + [contractName]: { + ...v, + path: path + } + }; + }, {}); + + return { + networkContracts, + version + }; +} diff --git a/scenario/src/Contract/CToken.ts b/scenario/src/Contract/CToken.ts new file mode 100644 index 000000000..85c7ce050 --- /dev/null +++ b/scenario/src/Contract/CToken.ts @@ -0,0 +1,57 @@ +import {Contract} from '../Contract'; +import {Callable, Sendable} from '../Invokation'; +import {encodedNumber} from '../Encoding'; + +interface CTokenMethods { + balanceOfUnderlying(string): Callable + borrowBalanceCurrent(string): Callable + borrowBalanceStored(string): Callable + totalBorrows(): Callable + totalBorrowsCurrent(): Callable + totalReserves(): Callable + reserveFactorMantissa(): Callable + comptroller(): Callable + exchangeRateStored(): Sendable + exchangeRateCurrent(): Callable + accrueInterest(): Sendable + mint(): Sendable + mint(encodedNumber): Sendable + redeem(encodedNumber): Sendable + redeemUnderlying(encodedNumber): Sendable + borrow(encodedNumber): Sendable + repayBorrow(): Sendable + repayBorrow(encodedNumber): Sendable + repayBorrowBehalf(string): Sendable + repayBorrowBehalf(string, encodedNumber): Sendable + liquidateBorrow(borrower: string, cTokenCollateral: string): Sendable + liquidateBorrow(borrower: string, repayAmount: encodedNumber, cTokenCollateral: string): Sendable + seize(liquidator: string, borrower: string, seizeTokens: encodedNumber): Sendable + evilSeize(treasure: string, liquidator: string, borrower: string, seizeTokens: encodedNumber): Sendable + _reduceReserves(encodedNumber): Sendable + _setReserveFactor(encodedNumber): Sendable + _setInterestRateModel(string): Sendable + _setComptroller(string): Sendable + underlying(): Callable + interestRateModel(): Callable + borrowRatePerBlock(): Callable + donate(): Sendable + admin(): Callable + pendingAdmin(): Callable + _setPendingAdmin(string): Sendable + _acceptAdmin(): Sendable +} + +interface CTokenScenarioMethods extends CTokenMethods { + setTotalBorrows(encodedNumber): Sendable + setTotalReserves(encodedNumber): Sendable +} + +export interface CToken extends Contract { + methods: CTokenMethods + name: string +} + +export interface CTokenScenario extends Contract { + methods: CTokenScenarioMethods + name: string +} diff --git a/scenario/src/Contract/Comptroller.ts b/scenario/src/Contract/Comptroller.ts new file mode 100644 index 000000000..8b650dcdd --- /dev/null +++ b/scenario/src/Contract/Comptroller.ts @@ -0,0 +1,40 @@ +import {Contract} from '../Contract'; +import {Callable, Sendable} from '../Invokation'; +import {encodedNumber} from '../Encoding'; + +interface ComptrollerMethods { + getAccountLiquidity(string): Callable<{0: number, 1: number, 2: number}> + getHypotheticalAccountLiquidity(account: string, asset: string, redeemTokens: encodedNumber, borrowAmount: encodedNumber): Callable<{0: number, 1: number, 2: number}> + membershipLength(string): Callable + checkMembership(user: string, cToken: string): Callable + getAssetsIn(string): Callable + admin(): Callable + oracle(): Callable + maxAssets(): Callable + liquidationIncentiveMantissa(): Callable + closeFactorMantissa(): Callable + blockNumber(): Callable + collateralFactor(string): Callable + markets(string): Callable<{0: boolean, 1: number}> + _setMintPaused(bool): Sendable + _setMaxAssets(encodedNumber): Sendable + _setLiquidationIncentive(encodedNumber): Sendable + _supportMarket(string): Sendable + _setPriceOracle(string): Sendable + _setCollateralFactor(string, encodedNumber): Sendable + _setCloseFactor(encodedNumber): Sendable + enterMarkets(markets: string[]): Sendable + exitMarket(market: string): Sendable + fastForward(encodedNumber): Sendable + _setPendingImplementation(string): Sendable + comptrollerImplementation(): Callable + unlist(string): Sendable + admin(): Callable + pendingAdmin(): Callable + _setPendingAdmin(string): Sendable + _acceptAdmin(): Sendable +} + +export interface Comptroller extends Contract { + methods: ComptrollerMethods +} diff --git a/scenario/src/Contract/ComptrollerImpl.ts b/scenario/src/Contract/ComptrollerImpl.ts new file mode 100644 index 000000000..75570535e --- /dev/null +++ b/scenario/src/Contract/ComptrollerImpl.ts @@ -0,0 +1,11 @@ +import {Contract} from '../Contract'; +import {Callable, Sendable} from '../Invokation'; +import {encodedNumber} from '../Encoding'; + +interface ComptrollerImplMethods { + _become(comptroller: string, priceOracle: string, maxAssets: encodedNumber, closeFactor: encodedNumber, reinitializing: boolean): Sendable +} + +export interface ComptrollerImpl extends Contract { + methods: ComptrollerImplMethods +} diff --git a/scenario/src/Contract/Erc20.ts b/scenario/src/Contract/Erc20.ts new file mode 100644 index 000000000..31ff9d39c --- /dev/null +++ b/scenario/src/Contract/Erc20.ts @@ -0,0 +1,24 @@ +import {Contract} from '../Contract'; +import {Callable, Sendable} from '../Invokation'; +import {encodedNumber} from '../Encoding'; + +interface Erc20Methods { + name(): Callable + symbol(): Callable + decimals(): Callable + totalSupply(): Callable + balanceOf(string): Callable + allowance(owner: string, spender: string): Callable + approve(address: string, amount: encodedNumber): Sendable + allocateTo(address: string, amount: encodedNumber): Sendable + transfer(address: string, amount: encodedNumber): Sendable + transferFrom(owner: string, spender: string, amount: encodedNumber): Sendable + setFail(fail: boolean): Sendable + pause(): Sendable + unpause(): Sendable +} + +export interface Erc20 extends Contract { + methods: Erc20Methods + name: string +} diff --git a/scenario/src/Contract/InterestRateModel.ts b/scenario/src/Contract/InterestRateModel.ts new file mode 100644 index 000000000..dd49ead05 --- /dev/null +++ b/scenario/src/Contract/InterestRateModel.ts @@ -0,0 +1,12 @@ +import {Contract} from '../Contract'; +import {Callable, Sendable} from '../Invokation'; +import {encodedNumber} from '../Encoding'; + +interface InterestRateModelMethods { + getBorrowRate(cash: encodedNumber, borrows: encodedNumber, reserves: encodedNumber): Callable<{0: number, 1: number}> +} + +export interface InterestRateModel extends Contract { + methods: InterestRateModelMethods + name: string +} diff --git a/scenario/src/Contract/Maximillion.ts b/scenario/src/Contract/Maximillion.ts new file mode 100644 index 000000000..02b955278 --- /dev/null +++ b/scenario/src/Contract/Maximillion.ts @@ -0,0 +1,11 @@ +import {Contract} from '../Contract'; +import {Callable, Sendable} from '../Invokation'; + +interface MaximillionMethods { + cEther(): Callable + repayBehalf(string): Sendable +} + +export interface Maximillion extends Contract { + methods: MaximillionMethods +} diff --git a/scenario/src/Contract/PriceOracle.ts b/scenario/src/Contract/PriceOracle.ts new file mode 100644 index 000000000..4ea9f8d58 --- /dev/null +++ b/scenario/src/Contract/PriceOracle.ts @@ -0,0 +1,29 @@ +import {Contract} from '../Contract'; +import {Callable, Sendable} from '../Invokation'; +import {encodedNumber} from '../Encoding'; + +interface PriceOracleMethods { + assetPrices(asset: string): Callable + setUnderlyingPrice(cToken: string, amount: encodedNumber): Sendable + + // Anchor Price Oracle + getPrice(asset: string): Callable + readers(asset: string): Callable + anchorAdmin(): Callable + pendingAnchorAdmin(): Callable + poster(): Callable + maxSwing(): Callable + anchors(asset: string): Callable<{0: number, 1: number}> + pendingAnchors(asset: string): Callable + _setPendingAnchor(asset: string, price: encodedNumber): Sendable + _setPaused(paused: boolean): Sendable + _setPendingAnchorAdmin(string): Sendable + _acceptAnchorAdmin(): Sendable + setPrice(asset: string, price: encodedNumber): Sendable + setPrices(assets: string[], prices: encodedNumber[]): Sendable +} + +export interface PriceOracle extends Contract { + methods: PriceOracleMethods + name: string +} diff --git a/scenario/src/Contract/PriceOracleProxy.ts b/scenario/src/Contract/PriceOracleProxy.ts new file mode 100644 index 000000000..155c06a60 --- /dev/null +++ b/scenario/src/Contract/PriceOracleProxy.ts @@ -0,0 +1,10 @@ +import {Contract} from '../Contract'; +import {Callable, Sendable} from '../Invokation'; + +interface PriceOracleProxyMethods { + getUnderlyingPrice(asset: string): Callable +} + +export interface PriceOracleProxy extends Contract { + methods: PriceOracleProxyMethods +} diff --git a/scenario/src/Contract/Unitroller.ts b/scenario/src/Contract/Unitroller.ts new file mode 100644 index 000000000..89704d6d2 --- /dev/null +++ b/scenario/src/Contract/Unitroller.ts @@ -0,0 +1,12 @@ +import {Contract} from '../Contract'; +import {Callable, Sendable} from '../Invokation'; + +interface UnitrollerMethods { + admin(): Callable + _setPendingImplementation(string): Sendable + comptrollerImplementation(): Callable +} + +export interface Unitroller extends Contract { + methods: UnitrollerMethods +} diff --git a/scenario/src/ContractLookup.ts b/scenario/src/ContractLookup.ts new file mode 100644 index 000000000..9682e5e11 --- /dev/null +++ b/scenario/src/ContractLookup.ts @@ -0,0 +1,158 @@ +import {Event} from './Event'; +import {World} from './World'; +import {accountMap} from './Accounts'; +import {Contract} from './Contract'; +import {mustString} from './Utils'; + +import {Comptroller} from './Contract/Comptroller'; +import {ComptrollerImpl} from './Contract/ComptrollerImpl'; +import {CToken} from './Contract/CToken'; +import {Erc20} from './Contract/Erc20'; +import {InterestRateModel} from './Contract/InterestRateModel'; +import {PriceOracle} from './Contract/PriceOracle'; +import {Map} from 'immutable'; + +type ContractDataEl = string | Map | null; + +function getContractData(world: World, indices: string[][]): ContractDataEl { + return indices.reduce((value: ContractDataEl, index) => { + if (value) { + return value; + } else { + return index.reduce((data: ContractDataEl, el) => { + let lowerEl = el.toLowerCase(); + + if (!data) { + return null; + } else if (typeof(data) === "string") { + return data; + } else { + return ( + Map(data).find( + (_v, key) => key.toLowerCase().trim() === lowerEl.trim())); + } + }, world.contractData); + } + }, null); +} + +function getContractDataString(world: World, indices: string[][]): string { + const value: ContractDataEl = getContractData(world, indices); + + if (!value || typeof(value) !== "string") { + throw new Error(`Failed to find string value by index (got ${value}): ${JSON.stringify(indices)}, index contains: ${JSON.stringify(world.contractData.toJSON())}`); + } + + return value; +} + +export function getWorldContract(world: World, indices: string[][]): T { + const address = getContractDataString(world, indices); + + return getWorldContractByAddress(world, address); +} + +export function getWorldContractByAddress(world: World, address: string): T { + const contract = world.contractIndex[address.toLowerCase()]; + + if (!contract) { + throw new Error(`Failed to find world contract by address: ${address}, index contains: ${JSON.stringify(Object.keys(world.contractIndex))}`); + } + + return contract; +} + +export async function getUnitroller(world: World): Promise { + return getWorldContract(world, [['Contracts', 'Unitroller']]); +} + +export async function getMaximillion(world: World): Promise { + return getWorldContract(world, [['Contracts', 'Maximillion']]); +} + +export async function getComptroller(world: World): Promise { + return getWorldContract(world, [['Contracts', 'Comptroller']]); +} + +export async function getComptrollerImpl(world: World, comptrollerImplArg: Event): Promise { + return getWorldContract(world, [['Comptroller', mustString(comptrollerImplArg), 'address']]); +} + +export function getCTokenAddress(world: World, cTokenArg: string): string { + return getContractDataString(world, [['cTokens', cTokenArg, 'address']]); +} + +export function getErc20Address(world: World, erc20Arg: string): string { + return getContractDataString(world, [['Tokens', erc20Arg, 'address']]); +} + +export async function getPriceOracleProxy(world: World): Promise { + return getWorldContract(world, [['Contracts', 'PriceOracleProxy']]); +} + +export async function getPriceOracle(world: World): Promise { + return getWorldContract(world, [['Contracts', 'PriceOracle']]); +} + +export async function getInterestRateModel(world: World, interestRateModelArg: Event): Promise { + return getWorldContract(world, [['InterestRateModel', mustString(interestRateModelArg), 'address']]); +} + +export async function getInterestRateModelData(world: World, interestRateModelArg: string): Promise<[InterestRateModel, string, Map]> { + let contract = await getInterestRateModel(world, interestRateModelArg); + let data = getContractData(world, [['InterestRateModel', interestRateModelArg]]); + + return [contract, interestRateModelArg, >data]; +} + +export async function getErc20Data(world: World, erc20Arg: string): Promise<[Erc20, string, Map]> { + let contract = getWorldContract(world, [['Tokens', erc20Arg, 'address']]); + let data = getContractData(world, [['Tokens', erc20Arg]]); + + return [contract, erc20Arg, >data]; +} + +export async function getCTokenData(world: World, cTokenArg: string): Promise<[CToken, string, Map]> { + let contract = getWorldContract(world, [['cTokens', cTokenArg, 'address']]); + let data = getContractData(world, [['CTokens', cTokenArg]]); + + return [contract, cTokenArg, >data]; +} + +export async function getComptrollerImplData(world: World, comptrollerImplArg: string): Promise<[ComptrollerImpl, string, Map]> { + let contract = await getComptrollerImpl(world, comptrollerImplArg); + let data = getContractData(world, [['Comptroller', comptrollerImplArg]]); + + return [contract, comptrollerImplArg, >data]; +} + +export function getAddress(world: World, addressArg: string): string { + if (addressArg.toLowerCase() === "zero") { + return "0x0000000000000000000000000000000000000000"; + } + + if (addressArg.startsWith("0x")) { + return addressArg; + } + + let alias = Object.entries(world.settings.aliases).find(([alias, addr]) => alias.toLowerCase() === addressArg.toLowerCase()); + if (alias) { + return alias[1]; + } + + let account = world.accounts.find((account) => account.name.toLowerCase() === addressArg.toLowerCase()); + if (account) { + return account.address; + } + + return getContractDataString(world, [ + ['Contracts', addressArg], + ['cTokens', addressArg, 'address'], + ['Tokens', addressArg, 'address'], + ['Comptroller', addressArg, 'address'] + ]); +} + +export function getContractByName(world: World, name: string): Contract { + return getWorldContract(world, [['Contracts', name]]); +} diff --git a/scenario/src/CoreEvent.ts b/scenario/src/CoreEvent.ts new file mode 100644 index 000000000..cc524130a --- /dev/null +++ b/scenario/src/CoreEvent.ts @@ -0,0 +1,565 @@ +import { + addAction, + checkExpectations, + checkInvariants, + clearInvariants, + describeUser, + holdInvariants, + setEvent, + World +} from './World'; +import {Event} from './Event'; +import { + getAddressV, + getEventV, + getNumberV, + getStringV +} from './CoreValue'; +import { + AddressV, + EventV, + NothingV, + NumberV, + StringV, + Value +} from './Value'; +import {Arg, Command, processCommandEvent, View} from './Command'; +import {assertionCommands, processAssertionEvent} from './Event/AssertionEvent'; +import {comptrollerCommands, processComptrollerEvent} from './Event/ComptrollerEvent'; +import {processUnitrollerEvent, unitrollerCommands} from './Event/UnitrollerEvent'; +import {comptrollerImplCommands, processComptrollerImplEvent} from './Event/ComptrollerImplEvent'; +import {cTokenCommands, processCTokenEvent} from './Event/CTokenEvent'; +import {erc20Commands, processErc20Event} from './Event/Erc20Event'; +import {interestRateModelCommands, processInterestRateModelEvent} from './Event/InterestRateModelEvent'; +import {priceOracleCommands, processPriceOracleEvent} from './Event/PriceOracleEvent'; +import {priceOracleProxyCommands, processPriceOracleProxyEvent} from './Event/PriceOracleProxyEvent'; +import {maximillionCommands, processMaximillionEvent} from './Event/MaximillionEvent'; +import {invariantCommands, processInvariantEvent} from './Event/InvariantEvent'; +import {expectationCommands, processExpectationEvent} from './Event/ExpectationEvent'; +import {processTrxEvent, trxCommands} from './Event/TrxEvent'; +import {fetchers, getCoreValue} from './CoreValue'; +import {formatEvent} from './Formatter'; +import {fallback} from './Invokation'; +import {sleep} from './Utils'; +import {Map} from 'immutable'; +import {encodedNumber} from './Encoding'; +import {printHelp} from './Help'; + +export class EventProcessingError extends Error { + error: Error + event: Event + + constructor(error: Error, event: Event) { + super(error.message); + + this.error = error; + this.event = event; + this.message = `Error: \`${this.error.toString()}\` when processing \`${formatEvent(this.event)}\``; + } +} + +export async function processEvents(originalWorld: World, events: Event[]): Promise { + return events.reduce(async (pWorld: Promise, event: Event): Promise => { + let world = await pWorld; + + try { + world = await processCoreEvent(setEvent(world, event), event, world.defaultFrom()); + } catch (err) { + if (world.verbose) { + console.error(err); + } + throw new EventProcessingError(err, event); + }; + + // Next, check any unchecked invariants + world = await checkInvariants(world); + + // Check any expectations + world = await checkExpectations(world); + + // Also clear trx related fields + world = world.set('trxInvokationOpts', Map({})); + world = world.set('newInvokation', false); + + if (!world) { + throw new Error(`Encountered null world result when processing event ${event[0]}: ${world}`); + } else if (!(world instanceof World)) { + throw new Error(`Encountered world result which was not isWorld when processing event ${event[0]}: ${world}`); + } + + return world; + }, Promise.resolve(originalWorld)); +} + +async function print(world: World, message: string): Promise { + world.printer.printLine(message); + + return world; +} + +async function inspect(world: World, string: string | null): Promise { + if (string !== null) { + console.log(["Inspect", string, world.toJS()]); + } else { + console.log(["Inspect", world.toJS()]); + } + + return world; +} + +async function sendEther(world: World, from: string, to: string, amount: encodedNumber): Promise { + let invokation = await fallback(world, from, to, amount); + + world = addAction( + world, + `Send ${amount} from ${from} to ${to}`, + invokation + ); + + return world; +} + +export const commands = [ + new View<{n: NumberV}>(` + #### History + + * "History n:=5" - Prints history of actions + * E.g. "History" + * E.g. "History 10" + `, + "History", + [ + new Arg("n", getNumberV, {default: new NumberV(5)}) + ], + async (world, {n}) => { + world.actions.slice(0, Number(n.val)).forEach((action) => { + world.printer.printLine(action.toString()); + }); + + return world; + } + ), + new View<{ms: NumberV}>(` + #### Sleep + + * "Sleep ms:" - Sleeps for given amount of time. + * E.g. "Sleep 1000" - Sleeps for one second + `, + "Sleep", + [ + new Arg("ms", getNumberV) + ], + async (world, {ms}) => { + await sleep(ms.toNumber()); + return world; + } + ), + new View<{errMsg: StringV}>(` + #### Throw + + * "Throw errMsg:" - Throws given error + * E.g. "Throw \"my error message\"" + `, + "Throw", + [ + new Arg("errMsg", getStringV) + ], + async (world, {errMsg}) => { + throw new Error(errMsg.val); + + return world; + } + ), + new View<{res: Value}>(` + #### Read + + * "Read ..." - Reads given value and prints result + * E.g. "Read CToken cBAT ExchangeRateStored" - Returns exchange rate of cBAT + `, + "Read", + [ + new Arg("res", getCoreValue, {variadic: true}) + ], + async (world, {res}) => { + world.printer.printValue(res); + + return world; + }, + { subExpressions: fetchers } + ), + new View<{message: StringV}>(` + #### Print + + * "Print ..." - Prints given string + * E.g. "Print \"Hello there\"" + `, + "Print", + [ + new Arg("message", getStringV) + ], + async (world, {message}) => print(world, message.val) + ), + new View<{address: AddressV}>(` + #### MyAddress + + * "MyAddress address:" - Sets default from address (same as "Alias Me ") + * E.g. "MyAddress \"0x9C1856636d78C051deAd6CAB9c5699e4E25549e9\"" + `, + "MyAddress", + [ + new Arg("address", getAddressV) + ], + async (world, {address}) => { + return await world.updateSettings(async (settings) => { + settings.aliases["Me"] = address.val; + + return settings; + }); + } + ), + new View<{name: StringV, address: AddressV}>(` + #### Alias + + * "Alias name: address:" - Stores an alias between name and address + * E.g. "Alias Me \"0x9C1856636d78C051deAd6CAB9c5699e4E25549e9\"" + `, + "Alias", + [ + new Arg("name", getStringV), + new Arg("address", getAddressV) + ], + async (world, {name, address}) => { + return await world.updateSettings(async (settings) => { + settings.aliases[name.val] = address.val; + + return settings; + }); + } + ), + new View<{name: StringV, address: AddressV}>(` + #### Aliases + + * "Aliases - Prints all aliases + `, + "Aliases", + [], + async (world, {name, address}) => { + world.printer.printLine("Aliases:"); + Object.entries(world.settings.aliases).forEach(([name, address]) => { + world.printer.printLine(`\t${name}: ${address}`); + }); + + return world; + } + ), + new View<{}>(` + #### Inspect + + * "Inspect" - Prints debugging information about the world + `, + "Inspect", + [], + async (world, {}) => inspect(world, null) + ), + new View<{message: StringV}>(` + #### Debug + + * "Debug message:" - Same as inspect but prepends with a string + `, + "Debug", + [ + new Arg("message", getStringV) + ], + async (world, {message}) => inspect(world, message.val) + ), + new View<{account: AddressV, event: EventV}>(` + #### From + + * "From " - Runs event as the given user + * E.g. "From Geoff (CToken cZRX Mint 5e18)" + `, + "From", + [ + new Arg("account", getAddressV), + new Arg("event", getEventV) + ], + async (world, {account, event}) => processCoreEvent(world, event.val, account.val) + ), + new Command<{event: EventV}>(` + #### Trx + + * "Trx ...trxEvent" - Handles event to set details of next transaction + * E.g. "Trx Value 1.0e18 (CToken cEth Mint 1.0e18)" + `, + "Trx", + [ + new Arg("event", getEventV, {variadic: true}) + ], + async (world, from, {event}) => processTrxEvent(world, event.val, from), + { subExpressions: trxCommands() } + ), + new Command<{event: EventV}>(` + #### Invariant + + * "Invariant ...invariant" - Adds a new invariant to the world which is checked after each transaction + * E.g. "Invariant Static (CToken cZRX TotalSupply)" + `, + "Invariant", + [ + new Arg("event", getEventV, {variadic: true}) + ], + async (world, from, {event}) => processInvariantEvent(world, event.val, from), + { subExpressions: invariantCommands() } + ), + new Command<{event: EventV}>(` + #### Expect + + * "Expect ...expectation" - Adds an expectation to hold after the next transaction + * E.g. "Expect Changes (CToken cZRX TotalSupply) +10.0e18" + `, + "Expect", + [ + new Arg("event", getEventV, {variadic: true}) + ], + async (world, from, {event}) => processExpectationEvent(world, event.val, from), + { subExpressions: expectationCommands() } + ), + new View<{type: StringV}>(` + #### HoldInvariants + + * "HoldInvariants type:" - Skips checking invariants on next command. + * E.g. "HoldInvariants" - Skips all invariants + * E.g. "HoldInvariants All" - Skips all invariants + * E.g. "HoldInvariants Success" - Skips "success" invariants + * E.g. "HoldInvariants Remains" - Skips "remains" invariants + * E.g. "HoldInvariants Static" - Skips "static" invariants + `, + "HoldInvariants", + [ + new Arg("type", getStringV, {default: new StringV("All")}) + ], + async (world, {type}) => holdInvariants(world, type.val) + ), + new View<{type: StringV}>(` + #### ClearInvariants + + * "ClearInvariants type:" - Removes all invariants. + * E.g. "ClearInvariants" - Removes all invariants + * E.g. "ClearInvariants All" - Removes all invariants + * E.g. "ClearInvariants Success" - Removes "success" invariants + * E.g. "ClearInvariants Remains" - Removes "remains" invariants + * E.g. "ClearInvariants Static" - Removes "static" invariants + `, + "ClearInvariants", + [ + new Arg("type", getStringV, {default: new StringV("All")}) + ], + async (world, {type}) => clearInvariants(world, type.val) + ), + new Command<{event: EventV}>(` + #### Assert + + * "Assert ...event" - Validates given assertion, raising an exception if assertion fails + * E.g. "Assert Equal (Erc20 BAT TokenBalance Geoff) (Exactly 5.0)" + `, + "Assert", + [ + new Arg("event", getEventV, {variadic: true}) + ], + async (world, from, {event}) => processAssertionEvent(world, event.val, from), + { subExpressions: assertionCommands() } + ), + new Command<{gate: Value, event: EventV}>(` + #### Gate + + * "Gate value event" - Runs event only if value is falsey. Thus, gate can be used to build idempotency. + * E.g. "Gate (Erc20 ZRX Address) (Erc20 Deploy BAT)" + `, + "Gate", + [ + new Arg("gate", getCoreValue, {rescue: new NothingV()}), + new Arg("event", getEventV) + ], + async (world, from, {gate, event}) => { + if (gate.truthy()) { + return world; + } else { + return processCoreEvent(world, event.val, from); + } + } + ), + new Command<{given: Value, event: EventV}>(` + #### Given + + * "Given value event" - Runs event only if value is truthy. Thus, given can be used to build existence checks. + * E.g. "Given ($var) (PriceOracle SetPrice cBAT $var)" + `, + "Given", + [ + new Arg("given", getCoreValue, {rescue: new NothingV()}), + new Arg("event", getEventV) + ], + async (world, from, {given, event}) => { + if (given.truthy()) { + return processCoreEvent(world, event.val, from); + } else { + return world; + } + } + ), + new Command<{address: AddressV, amount: NumberV}>(` + #### Send + + * "Send
" - Sends a given amount of eth to given address + * E.g. "Send cETH 0.5e18" + `, + "Send", + [ + new Arg("address", getAddressV), + new Arg("amount", getNumberV) + ], + (world, from, {address, amount}) => sendEther(world, from, address.val, amount.encode()) + ), + new Command<{event: EventV}>(` + #### Unitroller + + * "Unitroller ...event" - Runs given Unitroller event + * E.g. "Unitroller SetPendingImpl MyComptrollerImpl" + `, + "Unitroller", + [ + new Arg("event", getEventV, {variadic: true}) + ], + (world, from, {event}) => processUnitrollerEvent(world, event.val, from), + { subExpressions: unitrollerCommands() } + ), + new Command<{event: EventV}>(` + #### Comptroller + + * "Comptroller ...event" - Runs given Comptroller event + * E.g. "Comptroller _setReserveFactor 0.5" + `, + "Comptroller", + [ + new Arg("event", getEventV, {variadic: true}) + ], + (world, from, {event}) => processComptrollerEvent(world, event.val, from), + { subExpressions: comptrollerCommands() } + ), + new Command<{event: EventV}>(` + #### ComptrollerImpl + + * "ComptrollerImpl ...event" - Runs given ComptrollerImpl event + * E.g. "ComptrollerImpl MyImpl Become" + `, + "ComptrollerImpl", + [ + new Arg("event", getEventV, {variadic: true}) + ], + (world, from, {event}) => processComptrollerImplEvent(world, event.val, from), + { subExpressions: comptrollerImplCommands() } + ), + new Command<{event: EventV}>(` + #### CToken + + * "CToken ...event" - Runs given CToken event + * E.g. "CToken cZRX Mint 5e18" + `, + "CToken", + [ + new Arg("event", getEventV, {variadic: true}) + ], + (world, from, {event}) => processCTokenEvent(world, event.val, from), + { subExpressions: cTokenCommands() } + ), + new Command<{event: EventV}>(` + #### Erc20 + + * "Erc20 ...event" - Runs given Erc20 event + * E.g. "Erc20 ZRX Facuet Geoff 5e18" + `, + "Erc20", + [ + new Arg("event", getEventV, {variadic: true}) + ], + (world, from, {event}) => processErc20Event(world, event.val, from), + { subExpressions: erc20Commands() } + ), + new Command<{event: EventV}>(` + #### InterestRateModel + + * "InterestRateModel ...event" - Runs given interest rate model event + * E.g. "InterestRateModel Deploy Fixed StdRate 0.5" + `, + "InterestRateModel", + [ + new Arg("event", getEventV, {variadic: true}) + ], + (world, from, {event}) => processInterestRateModelEvent(world, event.val, from), + { subExpressions: interestRateModelCommands() } + ), + new Command<{event: EventV}>(` + #### PriceOracle + + * "PriceOracle ...event" - Runs given Price Oracle event + * E.g. "PriceOracle SetPrice cZRX 1.5" + `, + "PriceOracle", + [ + new Arg("event", getEventV, {variadic: true}) + ], + (world, from, {event}) => processPriceOracleEvent(world, event.val, from), + { subExpressions: priceOracleCommands() } + ), + new Command<{event: EventV}>(` + #### PriceOracleProxy + + * "PriceOracleProxy ...event" - Runs given Price Oracle event + * E.g. "PriceOracleProxy Deploy (Unitroller Address) (PriceOracle Address) (CToken cETH Address)" + `, + "PriceOracleProxy", + [ + new Arg("event", getEventV, {variadic: true}) + ], + (world, from, {event}) => { + return processPriceOracleProxyEvent(world, event.val, from) + }, + { subExpressions: priceOracleProxyCommands() } + ), + new Command<{event: EventV}>(` + #### Maximillion + + * "Maximillion ...event" - Runs given Maximillion event + * E.g. "Maximillion Deploy (CToken cETH Address)" + `, + "Maximillion", + [ + new Arg("event", getEventV, {variadic: true}) + ], + (world, from, {event}) => { + return processMaximillionEvent(world, event.val, from) + }, + { subExpressions: maximillionCommands() } + ), + new View<{event: EventV}>(` + #### Help + + * "Help ...event" - Prints help for given command + * E.g. "Help From" + `, + "Help", + [ + new Arg("event", getEventV, {variadic: true}) + ], + async (world, {event}) => { + world.printer.printLine(""); + printHelp(world.printer, event.val, commands); + + return world; + } + ) +]; + +export async function processCoreEvent(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("Core", commands, world, event, from); +} diff --git a/scenario/src/CoreValue.ts b/scenario/src/CoreValue.ts new file mode 100644 index 000000000..825fff3d4 --- /dev/null +++ b/scenario/src/CoreValue.ts @@ -0,0 +1,547 @@ +import {Event} from './Event'; +import {World} from './World'; +import { + AddressV, + AnythingV, + BoolV, + EventV, + ExpNumberV, + ListV, + MapV, + NothingV, + NumberV, + PercentV, + PreciseV, + StringV, + Value +} from './Value'; +import {Arg, Fetcher, getFetcherValue} from './Command'; +import {getUserValue, userFetchers} from './Value/UserValue'; +import {comptrollerFetchers, getComptrollerValue} from './Value/ComptrollerValue'; +import {comptrollerImplFetchers, getComptrollerImplValue} from './Value/ComptrollerImplValue'; +import {getUnitrollerValue, unitrollerFetchers} from './Value/UnitrollerValue'; +import {cTokenFetchers, getCTokenValue} from './Value/CTokenValue'; +import {erc20Fetchers, getErc20Value} from './Value/Erc20Value'; +import {getInterestRateModelValue, interestRateModelFetchers} from './Value/InterestRateModelValue'; +import {getPriceOracleValue, priceOracleFetchers} from './Value/PriceOracleValue'; +import {getPriceOracleProxyValue, priceOracleProxyFetchers} from './Value/PriceOracleProxyValue'; +import {getMaximillionValue, maximillionFetchers} from './Value/MaximillionValue'; +import {getAddress} from './ContractLookup'; +import {mustArray} from './Utils'; +import {toEncodableNum} from './Encoding'; +import {BigNumber} from 'bignumber.js'; + +const expMantissa = new BigNumber('1000000000000000000'); + +function getSigFigs(value) { + let str = value.toString(); + + str = str.replace(/e\d+/, ''); // Remove e01 + str = str.replace(/\./, ''); // Remove decimal point + + return str.length; +} + +export async function getEventV(world: World, event: Event): Promise { + return new EventV(event); +} + +// TODO: We may want to handle simple values -> complex values at the parser level +// This is currently trying to parse simple values as simple or complex values, +// and this is because items like `Some` could work either way. +export async function mapValue(world: World, event: Event, simple: (string) => T, complex: (World, Event) => Promise, type: any): Promise { + let simpleErr; + let val; + + if (typeof(event) === "string") { + try { + return simple(event); + } catch (err) { + // Collect the error, but fallback to a complex expression + simpleErr = err; + } + } + + try { + val = await complex(world, event); + } catch (complexErr) { + // If we had an error before and this was the fallback, now throw that one + if (simpleErr) { + throw simpleErr; + } else { + throw complexErr; + } + } + + if (!(val instanceof type)) { + throw new Error(`Expected ${type.name} from ${event.toString()}, got: ${val.toString()}`); + } + + // We just did a typecheck above... + return val; +} + +export async function getBoolV(world: World, event: Event): Promise { + return mapValue( + world, + event, + (str) => { + const lower = str.trim().toLowerCase(); + + if (lower == 'true' || lower == 't' || lower == '1') { + return new BoolV(true); + } else { + return new BoolV(false); + } + }, + getCoreValue, + BoolV + ); +} + +export async function getAddressV(world: World, event: Event): Promise { + return mapValue( + world, + event, + (str) => new AddressV(getAddress(world, str)), + async (currWorld, val) => { + const coreVal = await getCoreValue(currWorld, val); + + if (coreVal instanceof StringV) { + return new AddressV(coreVal.val); + } else { + return coreVal; + } + }, + AddressV + ); +} + +function strToNumberV(str: string): NumberV { + if (isNaN(Number(str))) { + throw "not a number"; + } + + return new NumberV(str); +} + +function strToExpNumberV(str: string): NumberV { + const r = new BigNumber(str); + + return new NumberV(r.multipliedBy(expMantissa).toFixed()); +} + +export async function getNumberV(world: World, event: Event): Promise { + return mapValue( + world, + event, + strToNumberV, + getCoreValue, + NumberV + ); +} + +export async function getExpNumberV(world: World, event: Event): Promise { + let res = await mapValue( + world, + event, + strToNumberV, + getCoreValue, + NumberV + ); + + const r = new BigNumber(res.val); + + return new ExpNumberV(r.multipliedBy(expMantissa).toFixed()); +} + +export async function getPercentV(world: World, event: Event): Promise { + let res = await getExpNumberV(world, event); + + return new PercentV(res.val); +} + +// Note: MapV does not currently parse its contents +export async function getMapV(world: World, event: Event): Promise { + const res: object = {}; + + await Promise.all(mustArray(event).map(async (e) => { + if (Array.isArray(e) && e.length === 2 && typeof e[0] === "string") { + const [key, valueEvent] = e; + let value; + if (typeof valueEvent === "string") { + value = new StringV(valueEvent); + } else { + value = await getCoreValue(world, valueEvent); + } + + res[key] = value; + } else { + throw new Error(`Expected all string pairs for MapV from ${event.toString()}, got: ${e.toString()}`); + } + })); + + return new MapV(res); +} + +export async function getStringV(world: World, event: Event): Promise { + return mapValue( + world, + event, + (str) => new StringV(str), + getCoreValue, + StringV + ); +} + +async function getEtherBalance(world: World, address: string): Promise { + let balance = await world.web3.eth.getBalance(address); + + return new NumberV(balance); +} + +export const fetchers = [ + new Fetcher<{}, BoolV>(` + #### True + + * "True" - Returns true + `, + "True", + [], + async (world, {}) => new BoolV(true) + ), + new Fetcher<{}, BoolV>(` + #### False + + * "False" - Returns false + `, + "False", + [], + async (world, {}) => new BoolV(false) + ), + new Fetcher<{}, NumberV>(` + #### Zero + + * "Zero" - Returns 0 + `, + "Zero", + [], + async (world, {}) => strToNumberV("0") + ), + new Fetcher<{}, NumberV>(` + #### Max + + * "Max" - Returns 2^256 - 1 + `, + "Max", + [], + async (world, {}) => new NumberV("115792089237316195423570985008687907853269984665640564039457584007913129639935") + ), + new Fetcher<{}, NumberV>(` + #### Some + + * "Some" - Returns 100e18 + `, + "Some", + [], + async (world, {}) => strToNumberV("100e18") + ), + new Fetcher<{}, NumberV>(` + #### Little + + * "Little" - Returns 100e10 + `, + "Little", + [], + async (world, {}) => strToNumberV("100e10") + ), + new Fetcher<{amt: EventV}, NumberV>(` + #### Exactly + + * "Exactly " - Returns a strict numerical value + * E.g. "Exactly 5.0" + `, + "Exactly", + [new Arg("amt", getEventV)], + async (world, {amt}) => getNumberV(world, amt.val) + ), + new Fetcher<{hexVal: EventV}, StringV>(` + #### Hex + + * "Hex " - Returns a byte string with given hex value + * E.g. "Hex \"0xffff\"" + `, + "Hex", + [new Arg("hexVal", getEventV)], + async (world, {hexVal}) => getStringV(world, hexVal.val) + ), + new Fetcher<{str: EventV}, StringV>(` + #### String + + * "String " - Returns a string literal + * E.g. "String MyString" + `, + "String", + [new Arg("str", getEventV)], + async (world, {str}) => getStringV(world, str.val) + ), + new Fetcher<{amt: EventV}, NumberV>(` + #### Exp + + * "Exp " - Returns the mantissa for a given exp + * E.g. "Exp 5.5" + `, + "Exp", + [new Arg("amt", getEventV)], + async (world, {amt}) => getExpNumberV(world, amt.val) + ), + new Fetcher<{amt: StringV}, PreciseV>(` + #### Precisely + + * "Precisely " - Matches a number to given number of significant figures + * E.g. "Exactly 5.1000" - Matches to 5 sig figs + `, + "Precisely", + [ + new Arg("amt", getStringV) + ], + async (world, {amt}) => new PreciseV(toEncodableNum(amt.val), getSigFigs(amt.val)) + ), + new Fetcher<{}, AnythingV>(` + #### Anything + + * "Anything" - Matches any value for assertions + `, + "Anything", + [], + async (world, {}) => new AnythingV() + ), + new Fetcher<{}, NothingV>(` + #### Nothing + + * "Nothing" - Matches no values and is nothing. + `, + "Nothing", + [], + async (world, {}) => new NothingV() + ), + new Fetcher<{addr: AddressV}, AddressV>(` + #### Address + + * "Address arg:
" - Returns an address + `, + "Address", + [ + new Arg("addr", getAddressV) + ], + async (world, {addr}) => addr + ), + new Fetcher<{}, AddressV>(` + #### LastContract + + * "LastContract" - The address of last constructed contract + `, + "LastContract", + [], + async (world, {}) => new AddressV(world.get('lastContract')) + ), + new Fetcher<{}, NumberV>(` + #### LastGas + + * "LastGas" - The gas consumed by the last transaction + `, + "LastGas", + [], + async (world, {}) => { + let invokation = world.get('lastInvokation'); + if (!invokation) { + throw new Error(`Expected last invokation for "lastGas" but none found.`); + } + + if (!invokation.receipt) { + throw new Error(`Expected last invokation to have receipt for "lastGas" but none found.`); + } + + return new NumberV(invokation.receipt.gasUsed); + } + ), + new Fetcher<{els: Value[]}, AnythingV>(` + #### List + + * "List ..." - Returns a list of given elements + `, + "List", + [ + new Arg("els", getCoreValue, {variadic: true, mapped: true}) + ], + async (world, {els}) => new ListV(els) + ), + new Fetcher<{val: Value, def: EventV}, Value>(` + #### Default + + * "Default val: def:" - Returns value if truthy, otherwise default. Note: this **does** short circuit. + `, + "Default", + [ + new Arg("val", getCoreValue), + new Arg("def", getEventV) + ], + async (world, {val, def}) => { + if (val.truthy()) { + return val; + } else { + return await getCoreValue(world, def.val); + } + } + ), + new Fetcher<{res: Value}, Value>(` + #### User + + * "User ...userArgs" - Returns user value + `, + "User", + [ + new Arg("res", getUserValue, {variadic: true}) + ], + async (world, {res}) => res, + { subExpressions: userFetchers() } + ), + new Fetcher<{address: AddressV}, Value>(` + #### EtherBalance + + * "EtherBalance
" - Returns given address' ether balance. + `, + "EtherBalance", + [ + new Arg("address", getAddressV) + ], + (world, {address}) => getEtherBalance(world, address.val) + ), + new Fetcher<{given: Value, expected: Value}, BoolV>(` + #### Equal + + * "Equal given: expected:" - Returns true if given values are equal + * E.g. "Equal (Exactly 0) Zero" + * E.g. "Equal (CToken cZRX TotalSupply) (Exactly 55)" + * E.g. "Equal (CToken cZRX Comptroller) (Comptroller Address)" + `, + "Equal", + [ + new Arg("given", getCoreValue), + new Arg("expected", getCoreValue) + ], + async (world, {given, expected}) => new BoolV(expected.compareTo(world, given)) + ), + new Fetcher<{res: Value}, Value>(` + #### Unitroller + + * "Unitroller ...unitrollerArgs" - Returns unitroller value + `, + "Unitroller", + [ + new Arg("res", getUnitrollerValue, {variadic: true}) + ], + async (world, {res}) => res, + { subExpressions: unitrollerFetchers() } + ), + new Fetcher<{res: Value}, Value>(` + #### Comptroller + + * "Comptroller ...comptrollerArgs" - Returns comptroller value + `, + "Comptroller", + [ + new Arg("res", getComptrollerValue, {variadic: true}) + ], + async (world, {res}) => res, + { subExpressions: comptrollerFetchers() } + ), + new Fetcher<{res: Value}, Value>(` + #### ComptrollerImpl + + * "ComptrollerImpl ...comptrollerImplArgs" - Returns comptroller implementation value + `, + "ComptrollerImpl", + [ + new Arg("res", getComptrollerImplValue, {variadic: true}) + ], + async (world, {res}) => res, + { subExpressions: comptrollerImplFetchers() } + ), + new Fetcher<{res: Value}, Value>(` + #### CToken + + * "CToken ...cTokenArgs" - Returns cToken value + `, + "CToken", + [ + new Arg("res", getCTokenValue, {variadic: true}) + ], + async (world, {res}) => res, + { subExpressions: cTokenFetchers() } + ), + new Fetcher<{res: Value}, Value>(` + #### Erc20 + + * "Erc20 ...erc20Args" - Returns Erc20 value + `, + "Erc20", + [ + new Arg("res", getErc20Value, {variadic: true}) + ], + async (world, {res}) => res, + { subExpressions: erc20Fetchers() } + ), + new Fetcher<{res: Value}, Value>(` + #### InterestRateModel + + * "InterestRateModel ...interestRateModelArgs" - Returns InterestRateModel value + `, + "InterestRateModel", + [ + new Arg("res", getInterestRateModelValue, {variadic: true}) + ], + async (world, {res}) => res, + { subExpressions: interestRateModelFetchers() } + ), + new Fetcher<{res: Value}, Value>(` + #### PriceOracle + + * "PriceOracle ...priceOracleArgs" - Returns PriceOracle value + `, + "PriceOracle", + [ + new Arg("res", getPriceOracleValue, {variadic: true}) + ], + async (world, {res}) => res, + { subExpressions: priceOracleFetchers() } + ), + new Fetcher<{res: Value}, Value>(` + #### PriceOracleProxy + + * "PriceOracleProxy ...priceOracleProxyArgs" - Returns PriceOracleProxy value + `, + "PriceOracleProxy", + [ + new Arg("res", getPriceOracleProxyValue, {variadic: true}) + ], + async (world, {res}) => res, + { subExpressions: priceOracleProxyFetchers() } + ), + new Fetcher<{res: Value}, Value>(` + #### Maximillion + + * "Maximillion ...maximillionArgs" - Returns Maximillion value + `, + "Maximillion", + [ + new Arg("res", getMaximillionValue, {variadic: true}) + ], + async (world, {res}) => res, + { subExpressions: maximillionFetchers() } + ) +]; + +export async function getCoreValue(world: World, event: Event): Promise { + return await getFetcherValue("Core", fetchers, world, event); +} diff --git a/scenario/src/Encoding.ts b/scenario/src/Encoding.ts new file mode 100644 index 000000000..5d9d278df --- /dev/null +++ b/scenario/src/Encoding.ts @@ -0,0 +1,37 @@ +import BigNumber from 'bignumber.js'; +import { utils, ethers } from 'ethers'; + +const smallEnoughNumber = new BigNumber('100000000'); + +export type encodedNumber = number | utils.BigNumber; + +// Returns the mantissa of an Exp with given floating value +export function getExpMantissa(float: number): encodedNumber { + // Workaround from https://github.com/ethereum/web3.js/issues/1920 + const str = Math.floor(float * 1.0e18).toString(); + + return toEncodableNum(str); +} + +export function toEncodableNum(amountArgRaw: string | encodedNumber): encodedNumber { + let bigNumber; + if (amountArgRaw instanceof BigNumber) { + bigNumber = amountArgRaw; + } else { + bigNumber = new BigNumber(amountArgRaw.toString()); + } + + if (bigNumber.lt(smallEnoughNumber)) { + // The Ethers abi encoder can handle regular numbers (including with fractional part) + // and its own internal big number class which is different from BigNumber.js published on npm (and can't accept + // fractional parts.) + // If the input is not huge, we just use a number, otherwise we try to use the Ethers class. + + return Number(amountArgRaw); + } else { + // bigNumberify (and the result class) only accept integers as digits, so we do .toFixed() to convert, for example, 1e4 to 10000. + // Rather than doing toFixed(0) and silently truncating a fractional part, we'll let it through and get an error. + // that case + return utils.bigNumberify(bigNumber.toFixed()); + } +} diff --git a/scenario/src/ErrorReporter.ts b/scenario/src/ErrorReporter.ts new file mode 100644 index 000000000..820b30aa1 --- /dev/null +++ b/scenario/src/ErrorReporter.ts @@ -0,0 +1,98 @@ +import {ComptrollerErr, TokenErr} from './ErrorReporterConstants'; + +export interface ErrorReporter { + getError(error: any): string | null + getInfo(info: any): string | null + getDetail(error: any, detail: number): string +} + +class NoErrorReporterType implements ErrorReporter { + getError(error: any): string | null { + return null; + } + + getInfo(info: any): string | null { + return null; + } + + getDetail(error: any, detail: number): string { + return detail.toString(); + } +} + +class CTokenErrorReporterType implements ErrorReporter { + getError(error: any): string | null { + if (error === null) { + return null; + } else { + return TokenErr.ErrorInv[Number(error)]; + } + } + + getInfo(info: any): string | null { + if (info === null) { + return null; + } else { + return TokenErr.FailureInfoInv[Number(info)]; + } + } + + getDetail(error: any, detail: number): string { + // Little hack to let us use proper names for cross-contract errors + if (this.getError(error) === "COMPTROLLER_REJECTION") { + let comptrollerError = ComptrollerErrorReporter.getError(detail); + + if (comptrollerError) { + return comptrollerError; + } + } + + return detail.toString(); + } +} + +class ComptrollerErrorReporterType implements ErrorReporter { + getError(error: any): string | null { + if (error === null) { + return null; + } else { + // TODO: This probably isn't right... + return ComptrollerErr.ErrorInv[Number(error)]; + } + } + + getInfo(info: any): string | null { + if (info === null) { + return null; + } else { + // TODO: This probably isn't right... + return ComptrollerErr.FailureInfoInv[Number(info)]; + } + } + + getDetail(error: any, detail: number): string { + if (this.getError(error) === "REJECTION") { + let comptrollerError = ComptrollerErrorReporter.getError(detail); + + if (comptrollerError) { + return comptrollerError; + } + } + + return detail.toString(); + } +} + +export function formatResult(errorReporter: ErrorReporter, result: any): string { + const errorStr = errorReporter.getError(result); + if (errorStr !== null) { + return `Error=${errorStr}` + } else { + return `Result=${result}`; + } +} + +// Singleton instances +export const NoErrorReporter = new NoErrorReporterType(); +export const CTokenErrorReporter = new CTokenErrorReporterType(); +export const ComptrollerErrorReporter = new ComptrollerErrorReporterType(); diff --git a/scenario/src/ErrorReporterConstants.ts b/scenario/src/ErrorReporterConstants.ts new file mode 100644 index 000000000..159180659 --- /dev/null +++ b/scenario/src/ErrorReporterConstants.ts @@ -0,0 +1,183 @@ + +interface ErrorReporterEnum { + Error: string[] + FailureInfo: string[] +} + +interface ErrorTypes { + Error: {[name: string]: number} + FailureInfo: {[name: string]: number} + ErrorInv: {[code: number]: string} + FailureInfoInv: {[code: number]: string} +} + +const ComptrollerErrorReporter = { + Error: [ + 'NO_ERROR', + 'UNAUTHORIZED', + 'COMPTROLLER_MISMATCH', + 'INSUFFICIENT_SHORTFALL', + 'INSUFFICIENT_LIQUIDITY', + 'INVALID_CLOSE_FACTOR', + 'INVALID_COLLATERAL_FACTOR', + 'INVALID_LIQUIDATION_INCENTIVE', + 'MARKET_NOT_ENTERED', + 'MARKET_NOT_LISTED', + 'MARKET_ALREADY_LISTED', + 'MATH_ERROR', + 'NONZERO_BORROW_BALANCE', + 'PRICE_ERROR', + 'REJECTION', + 'SNAPSHOT_ERROR', + 'TOO_MANY_ASSETS', + 'TOO_MUCH_REPAY' + ], + + FailureInfo: [ + 'ACCEPT_ADMIN_PENDING_ADMIN_CHECK', + 'ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK', + 'EXIT_MARKET_BALANCE_OWED', + 'EXIT_MARKET_REJECTION', + 'SET_CLOSE_FACTOR_OWNER_CHECK', + 'SET_CLOSE_FACTOR_VALIDATION', + 'SET_COLLATERAL_FACTOR_OWNER_CHECK', + 'SET_COLLATERAL_FACTOR_NO_EXISTS', + 'SET_COLLATERAL_FACTOR_VALIDATION', + 'SET_COLLATERAL_FACTOR_WITHOUT_PRICE', + 'SET_IMPLEMENTATION_OWNER_CHECK', + 'SET_LIQUIDATION_INCENTIVE_OWNER_CHECK', + 'SET_LIQUIDATION_INCENTIVE_VALIDATION', + 'SET_MAX_ASSETS_OWNER_CHECK', + 'SET_PENDING_ADMIN_OWNER_CHECK', + 'SET_PENDING_IMPLEMENTATION_OWNER_CHECK', + 'SET_PRICE_ORACLE_OWNER_CHECK', + 'SUPPORT_MARKET_EXISTS', + 'SUPPORT_MARKET_OWNER_CHECK', + 'ZUNUSED' + ] +}; + +const TokenErrorReporter = { + Error: [ + 'NO_ERROR', + 'UNAUTHORIZED', + 'BAD_INPUT', + 'COMPTROLLER_REJECTION', + 'COMPTROLLER_CALCULATION_ERROR', + 'INTEREST_RATE_MODEL_ERROR', + 'INVALID_ACCOUNT_PAIR', + 'INVALID_CLOSE_AMOUNT_REQUESTED', + 'INVALID_COLLATERAL_FACTOR', + 'MATH_ERROR', + 'MARKET_NOT_FRESH', + 'MARKET_NOT_LISTED', + 'TOKEN_INSUFFICIENT_ALLOWANCE', + 'TOKEN_INSUFFICIENT_BALANCE', + 'TOKEN_INSUFFICIENT_CASH', + 'TOKEN_TRANSFER_IN_FAILED', + 'TOKEN_TRANSFER_OUT_FAILED' + ], + + FailureInfo: [ + 'ACCEPT_ADMIN_PENDING_ADMIN_CHECK', + 'ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED', + 'ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED', + 'ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED', + 'ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED', + 'ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED', + 'ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED', + 'BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED', + 'BORROW_ACCRUE_INTEREST_FAILED', + 'BORROW_CASH_NOT_AVAILABLE', + 'BORROW_FRESHNESS_CHECK', + 'BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED', + 'BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED', + 'BORROW_MARKET_NOT_LISTED', + 'BORROW_COMPTROLLER_REJECTION', + 'LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED', + 'LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED', + 'LIQUIDATE_COLLATERAL_FRESHNESS_CHECK', + 'LIQUIDATE_COMPTROLLER_REJECTION', + 'LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED', + 'LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX', + 'LIQUIDATE_CLOSE_AMOUNT_IS_ZERO', + 'LIQUIDATE_FRESHNESS_CHECK', + 'LIQUIDATE_LIQUIDATOR_IS_BORROWER', + 'LIQUIDATE_REPAY_BORROW_FRESH_FAILED', + 'LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED', + 'LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED', + 'LIQUIDATE_SEIZE_COMPTROLLER_REJECTION', + 'LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER', + 'LIQUIDATE_SEIZE_TOO_MUCH', + 'MINT_ACCRUE_INTEREST_FAILED', + 'MINT_COMPTROLLER_REJECTION', + 'MINT_EXCHANGE_CALCULATION_FAILED', + 'MINT_EXCHANGE_RATE_READ_FAILED', + 'MINT_FRESHNESS_CHECK', + 'MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED', + 'MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED', + 'MINT_TRANSFER_IN_FAILED', + 'MINT_TRANSFER_IN_NOT_POSSIBLE', + 'REDEEM_ACCRUE_INTEREST_FAILED', + 'REDEEM_COMPTROLLER_REJECTION', + 'REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED', + 'REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED', + 'REDEEM_EXCHANGE_RATE_READ_FAILED', + 'REDEEM_FRESHNESS_CHECK', + 'REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED', + 'REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED', + 'REDEEM_TRANSFER_OUT_NOT_POSSIBLE', + 'REDUCE_RESERVES_ACCRUE_INTEREST_FAILED', + 'REDUCE_RESERVES_ADMIN_CHECK', + 'REDUCE_RESERVES_CASH_NOT_AVAILABLE', + 'REDUCE_RESERVES_FRESH_CHECK', + 'REDUCE_RESERVES_VALIDATION', + 'REPAY_BEHALF_ACCRUE_INTEREST_FAILED', + 'REPAY_BORROW_ACCRUE_INTEREST_FAILED', + 'REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED', + 'REPAY_BORROW_COMPTROLLER_REJECTION', + 'REPAY_BORROW_FRESHNESS_CHECK', + 'REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED', + 'REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED', + 'REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE', + 'SET_COLLATERAL_FACTOR_OWNER_CHECK', + 'SET_COLLATERAL_FACTOR_VALIDATION', + 'SET_COMPTROLLER_OWNER_CHECK', + 'SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED', + 'SET_INTEREST_RATE_MODEL_FRESH_CHECK', + 'SET_INTEREST_RATE_MODEL_OWNER_CHECK', + 'SET_MAX_ASSETS_OWNER_CHECK', + 'SET_ORACLE_MARKET_NOT_LISTED', + 'SET_PENDING_ADMIN_OWNER_CHECK', + 'SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED', + 'SET_RESERVE_FACTOR_ADMIN_CHECK', + 'SET_RESERVE_FACTOR_FRESH_CHECK', + 'SET_RESERVE_FACTOR_BOUNDS_CHECK', + 'TRANSFER_COMPTROLLER_REJECTION', + 'TRANSFER_NOT_ALLOWED', + 'TRANSFER_NOT_ENOUGH', + 'TRANSFER_TOO_MUCH' + ] +}; + +function parseEnum(reporterEnum: ErrorReporterEnum): ErrorTypes { + const Error: {[name: string]: number} = {}; + const ErrorInv: {[code: number]: string} = {}; + const FailureInfo: {[name: string]: number} = {}; + const FailureInfoInv: {[code: number]: string} = {}; + + reporterEnum.Error.forEach((entry, i) => { + Error[entry] = i; + ErrorInv[i] = entry; + }); + + reporterEnum.FailureInfo.forEach((entry, i) => { + FailureInfo[entry] = i; + FailureInfoInv[i] = entry; + }); + + return {Error, ErrorInv, FailureInfo, FailureInfoInv}; +} + +export const ComptrollerErr = parseEnum(ComptrollerErrorReporter); +export const TokenErr = parseEnum(TokenErrorReporter); diff --git a/scenario/src/Event.ts b/scenario/src/Event.ts new file mode 100644 index 000000000..b5eb6e373 --- /dev/null +++ b/scenario/src/Event.ts @@ -0,0 +1,7 @@ + +type ScalarEvent = string; +interface EventArray extends Array { + [index: number]: ScalarEvent | EventArray; +} + +export type Event = EventArray; diff --git a/scenario/src/Event/AssertionEvent.ts b/scenario/src/Event/AssertionEvent.ts new file mode 100644 index 000000000..0fa52505f --- /dev/null +++ b/scenario/src/Event/AssertionEvent.ts @@ -0,0 +1,345 @@ +import {Event} from '../Event'; +import {fail, World} from '../World'; +import {mustArray} from '../Utils'; +import {getCoreValue} from '../CoreValue'; +import {formatError} from '../Formatter'; +import {Failure, Invokation, InvokationRevertFailure} from '../Invokation'; +import {formatEvent} from '../Formatter'; +import { + getAddressV, + getBoolV, + getEventV, + getMapV, + getNumberV, + getStringV +} from '../CoreValue'; +import { + AddressV, + BoolV, + EventV, + MapV, + NumberV, + Order, + StringV, + Value +} from '../Value'; +import {Arg, View, processCommandEvent} from '../Command'; + +async function assertEqual(world: World, given: Value, expected: Value): Promise { + if (!expected.compareTo(world, given)) { + return fail(world, `Expected ${given.toString()} to equal ${expected.toString()}`); + } + + return world; +} + +async function assertLessThan(world: World, given: Value, expected: Value): Promise { + if (given.compareOrder(world, expected) !== Order.LESS_THAN) { + return fail(world, `Expected ${given.toString()} to be less than ${expected.toString()}`); + } + + return world; +} + +async function assertFailure(world: World, failure: Failure): Promise { + if (!world.lastInvokation) { + return fail(world, `Expected ${failure.toString()}, but missing any invokations.`); + } + + if (world.lastInvokation.success()) { + return fail(world, `Expected ${failure.toString()}, but last invokation was successful with result ${JSON.stringify(world.lastInvokation.value)}.`); + } + + if (world.lastInvokation.error) { + return fail(world, `Expected ${failure.toString()}, but last invokation threw error ${world.lastInvokation.error}.`); + } + + if (world.lastInvokation.failures.length === 0) { + throw new Error(`Invokation requires success, failure or error, got: ${world.lastInvokation.toString()}`); + } + + if (world.lastInvokation.failures.find((f) => f.equals(failure)) === undefined) { + return fail(world, `Expected ${failure.toString()}, but got ${world.lastInvokation.failures.toString()}.`); + } + + return world; +} + +async function assertRevertFailure(world: World, err: string, message: string): Promise { + if (!world.lastInvokation) { + return fail(world, `Expected revert failure, but missing any invokations.`); + } + + if (world.lastInvokation.success()) { + return fail(world, `Expected revert failure, but last invokation was successful with result ${JSON.stringify(world.lastInvokation.value)}.`); + } + + if (world.lastInvokation.failures.length > 0) { + return fail(world, `Expected revert failure, but got ${world.lastInvokation.failures.toString()}.`); + } + + if (!world.lastInvokation.error) { + throw new Error(`Invokation requires success, failure or error, got: ${world.lastInvokation.toString()}`); + } + + if (!(world.lastInvokation.error instanceof InvokationRevertFailure)) { + throw new Error(`Invokation error mismatch, expected revert failure: "${err}, ${message}", got: "${world.lastInvokation.error.toString()}"`); + } + + const expectedMessage = `Returned error: VM Exception while processing transaction: ${message}`; + + if (world.lastInvokation.error.error !== err || world.lastInvokation.error.errMessage !== expectedMessage) { + throw new Error(`Invokation error mismatch, expected revert failure: err=${err}, message="${expectedMessage}", got: "${world.lastInvokation.error.toString()}"`); + } + + return world; +} + +async function assertError(world: World, message: string): Promise { + if (!world.lastInvokation) { + return fail(world, `Expected revert, but missing any invokations.`); + } + + if (world.lastInvokation.success()) { + return fail(world, `Expected revert, but last invokation was successful with result ${JSON.stringify(world.lastInvokation.value)}.`); + } + + if (world.lastInvokation.failures.length > 0) { + return fail(world, `Expected revert, but got ${world.lastInvokation.failures.toString()}.`); + } + + if (!world.lastInvokation.error) { + throw new Error(`Invokation requires success, failure or error, got: ${world.lastInvokation.toString()}`); + } + + if (!world.lastInvokation.error.message.startsWith(message)) { + throw new Error(`Invokation error mismatch, expected: "${message}", got: "${world.lastInvokation.error.message}"`); + } + + return world; +} + +function buildRevertMessage(world: World, message: string): string { + return `Returned error: VM Exception while processing transaction: ${message}` +} + +async function assertRevert(world: World, message: string): Promise { + return await assertError(world, buildRevertMessage(world, message)); +} + +async function assertSuccess(world: World): Promise { + if (!world.lastInvokation || world.lastInvokation.success()) { + return world; + } else { + return fail(world, `Expected success, but got ${world.lastInvokation.toString()}.`); + } +} + +async function assertReadError(world: World, event: Event, message: string, isRevert: boolean): Promise { + try { + let value = await getCoreValue(world, event); + + throw new Error(`Expected read revert, instead got value \`${value}\``); + } catch (err) { + let expectedMessage; + if (isRevert) { + expectedMessage = buildRevertMessage(world, message); + } else { + expectedMessage = message; + } + + world.assert.equal(expectedMessage, err.message, "expected read revert"); + } + + return world; +} + +async function assertLog(world: World, event: string, keyValues: MapV): Promise { + if (!world.lastInvokation) { + return fail(world, `Expected log message "${event}" from contract execution, but world missing any invokations.`); + } else if (!world.lastInvokation.receipt) { + return fail(world, `Expected log message "${event}" from contract execution, but world invokation transaction.`); + } else { + const log = world.lastInvokation.receipt.events[event]; + + if (!log) { + const events = Object.keys(world.lastInvokation.receipt.events).join(', '); + + fail(world, `Expected log with event \`${event}\`, found logs with events: [${events}]`); + } + + Object.entries(keyValues.val).forEach(([key, value]) => { + if (log.returnValues[key] === undefined) { + fail(world, `Expected log to have param for \`${key}\``); + } else { + let logValue = new StringV(log.returnValues[key]); + + if (!value.compareTo(world, logValue)) { + fail(world, `Expected log to have param \`${key}\` to match ${value.toString()}, but got ${logValue.toString()}`); + } + } + }); + + return world; + } +} + +export function assertionCommands() { + return [ + new View<{given: Value, expected: Value}>(` + #### Equal + + * "Equal given: expected:" - Asserts that given matches expected. + * E.g. "Assert Equal (Exactly 0) Zero" + * E.g. "Assert Equal (CToken cZRX TotalSupply) (Exactly 55)" + * E.g. "Assert Equal (CToken cZRX Comptroller) (Comptroller Address)" + `, + "Equal", + [ + new Arg("given", getCoreValue), + new Arg("expected", getCoreValue) + ], + (world, {given, expected}) => assertEqual(world, given, expected) + ), + new View<{given: Value, expected: Value}>(` + #### LessThan + + * "given: LastThan expected:" - Asserts that given matches expected. + * E.g. "Assert (Exactly 0) LessThan (Exactly 1)" + `, + "LessThan", + [ + new Arg("given", getCoreValue), + new Arg("expected", getCoreValue) + ], + (world, {given, expected}) => assertLessThan(world, given, expected), + {namePos: 1} + ), + new View<{given: Value}>(` + #### True + + * "True given:" - Asserts that given is true. + * E.g. "Assert True (Comptroller CheckMembership Geoff cETH)" + `, + "True", + [ + new Arg("given", getCoreValue) + ], + (world, {given}) => assertEqual(world, given, new BoolV(true)) + ), + new View<{given: Value}>(` + #### False + + * "False given:" - Asserts that given is false. + * E.g. "Assert False (Comptroller CheckMembership Geoff cETH)" + `, + "False", + [ + new Arg("given", getCoreValue) + ], + (world, {given}) => assertEqual(world, given, new BoolV(false)) + ), + new View<{event: EventV, message: StringV}>(` + #### ReadRevert + + * "ReadRevert event: message:" - Asserts that reading the given value reverts with given message. + * E.g. "Assert ReadRevert (Comptroller CheckMembership Geoff cETH) \"revert\"" + `, + "ReadRevert", + [ + new Arg("event", getEventV), + new Arg("message", getStringV) + ], + (world, {event, message}) => assertReadError(world, event.val, message.val, true) + ), + new View<{event: EventV, message: StringV}>(` + #### ReadError + + * "ReadError event: message:" - Asserts that reading the given value throws given error + * E.g. "Assert ReadError (Comptroller Bad Address) \"cannot find comptroller\"" + `, + "ReadError", + [ + new Arg("event", getEventV), + new Arg("message", getStringV) + ], + (world, {event, message}) => assertReadError(world, event.val, message.val, false) + ), + new View<{error: StringV, info: StringV, detail: StringV}>(` + #### Failure + + * "Failure error: info: detail:" - Asserts that last transaction had a graceful failure with given error, info and detail. + * E.g. "Assert Failure UNAUTHORIZED SUPPORT_MARKET_OWNER_CHECK" + * E.g. "Assert Failure MATH_ERROR MINT_CALCULATE_BALANCE 5" + `, + "Failure", + [ + new Arg("error", getStringV), + new Arg("info", getStringV), + new Arg("detail", getStringV, {default: new StringV("0")}), + ], + (world, {error, info, detail}) => assertFailure(world, new Failure(error.val, info.val, detail.val)) + ), + new View<{error: StringV, message: StringV}>(` + #### RevertFailure + + * "RevertFailure error: message:" - Assert last transaction reverted with a message beginning with an error code + * E.g. "Assert RevertFailure UNAUTHORIZED \"set reserves failed\"" + `, + "RevertFailure", + [ + new Arg("error", getStringV), + new Arg("message", getStringV), + ], + (world, {error, message}) => assertRevertFailure(world, error.val, message.val) + ), + new View<{message: StringV}>(` + #### Revert + + * "Revert message:" - Asserts that the last transaction reverted. + `, + "Revert", + [ + new Arg("message", getStringV, {default: new StringV("revert")}), + ], + (world, {message}) => assertRevert(world, message.val) + ), + new View<{message: StringV}>(` + #### Error + + * "Error message:" - Asserts that the last transaction had the given error. + `, + "Error", + [ + new Arg("message", getStringV), + ], + (world, {message}) => assertError(world, message.val) + ), + new View<{given: Value}>(` + #### Success + + * "Success" - Asserts that the last transaction completed successfully (that is, did not revert nor emit graceful failure). + `, + "Success", + [], + (world, {given}) => assertSuccess(world) + ), + new View<{name: StringV, params: MapV}>(` + #### Log + + * "Log name: (key: value:) ..." - Asserts that last transaction emitted log with given name and key-value pairs. + * E.g. "Assert Log Minted ("account" (User Geoff address)) ("amount" (Exactly 55))" + `, + "Log", + [ + new Arg("name", getStringV), + new Arg("params", getMapV, {variadic: true}), + ], + (world, {name, params}) => assertLog(world, name.val, params) + ) + ]; +} + +export async function processAssertionEvent(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("Assertion", assertionCommands(), world, event, from); +} diff --git a/scenario/src/Event/CTokenEvent.ts b/scenario/src/Event/CTokenEvent.ts new file mode 100644 index 000000000..119ddcfcb --- /dev/null +++ b/scenario/src/Event/CTokenEvent.ts @@ -0,0 +1,717 @@ +import {Event} from '../Event'; +import {addAction, describeUser, World} from '../World'; +import {decodeCall, getPastEvents} from '../Contract'; +import {CToken, CTokenScenario} from '../Contract/CToken'; +import {invoke, Sendable} from '../Invokation'; +import { + getAddressV, + getEventV, + getExpNumberV, + getNumberV, + getStringV +} from '../CoreValue'; +import { + AddressV, + EventV, + NothingV, + NumberV, + StringV} from '../Value'; +import {Arg, Command, View, processCommandEvent} from '../Command'; +import {CTokenErrorReporter} from '../ErrorReporter'; +import {getComptroller, getCTokenData} from '../ContractLookup'; +import {getExpMantissa} from '../Encoding'; +import {buildCToken} from '../Builder/CTokenBuilder'; +import {verify} from '../Verify'; +import {getLiquidity} from '../Value/ComptrollerValue'; +import {encodedNumber} from '../Encoding'; +import {getCTokenV} from '../Value/CTokenValue'; + +function showTrxValue(world: World): string { + return new NumberV(world.trxInvokationOpts.get('value')).show(); +} + +async function genCToken(world: World, from: string, event: Event): Promise { + let {world: nextWorld, cToken, tokenData} = await buildCToken(world, from, event); + world = nextWorld; + + world = addAction( + world, + `Added cToken ${tokenData.name} (${tokenData.contract}) at address ${cToken._address}`, + tokenData.invokation + ); + + return world; +} + +async function accrueInterest(world: World, from: string, cToken: CToken): Promise { + let invokation = await invoke(world, cToken.methods.accrueInterest(), from, CTokenErrorReporter); + + world = addAction( + world, + `CToken ${cToken.name}: Interest accrued`, + invokation + ); + + return world; +} + +async function mint(world: World, from: string, cToken: CToken, amount: NumberV | NothingV): Promise { + let invokation; + let showAmount; + + if (amount instanceof NumberV) { + showAmount = amount.show(); + invokation = await invoke(world, cToken.methods.mint(amount.encode()), from, CTokenErrorReporter); + } else { + showAmount = showTrxValue(world); + invokation = await invoke(world, cToken.methods.mint(), from, CTokenErrorReporter); + } + + world = addAction( + world, + `CToken ${cToken.name}: ${describeUser(world, from)} mints ${showAmount}`, + invokation + ); + + return world; +} + +async function redeem(world: World, from: string, cToken: CToken, tokens: NumberV): Promise { + let invokation = await invoke(world, cToken.methods.redeem(tokens.encode()), from, CTokenErrorReporter); + + world = addAction( + world, + `CToken ${cToken.name}: ${describeUser(world, from)} redeems ${tokens.show()} tokens`, + invokation + ); + + return world; +} + +async function redeemUnderlying(world: World, from: string, cToken: CToken, amount: NumberV): Promise { + let invokation = await invoke(world, cToken.methods.redeemUnderlying(amount.encode()), from, CTokenErrorReporter); + + world = addAction( + world, + `CToken ${cToken.name}: ${describeUser(world, from)} redeems ${amount.show()} underlying`, + invokation + ); + + return world; +} + +async function borrow(world: World, from: string, cToken: CToken, amount: NumberV): Promise { + let invokation = await invoke(world, cToken.methods.borrow(amount.encode()), from, CTokenErrorReporter); + + world = addAction( + world, + `CToken ${cToken.name}: ${describeUser(world, from)} borrows ${amount.show()}`, + invokation + ); + + return world; +} + +async function repayBorrow(world: World, from: string, cToken: CToken, amount: NumberV | NothingV): Promise { + let invokation; + let showAmount; + + if (amount instanceof NumberV) { + showAmount = amount.show(); + invokation = await invoke(world, cToken.methods.repayBorrow(amount.encode()), from, CTokenErrorReporter); + } else { + showAmount = showTrxValue(world); + invokation = await invoke(world, cToken.methods.repayBorrow(), from, CTokenErrorReporter); + } + + world = addAction( + world, + `CToken ${cToken.name}: ${describeUser(world, from)} repays ${showAmount} of borrow`, + invokation + ); + + return world; +} + +async function repayBorrowBehalf(world: World, from: string, behalf: string, cToken: CToken, amount: NumberV | NothingV): Promise { + let invokation; + let showAmount; + + if (amount instanceof NumberV) { + showAmount = amount.show(); + invokation = await invoke(world, cToken.methods.repayBorrowBehalf(behalf, amount.encode()), from, CTokenErrorReporter); + } else { + showAmount = showTrxValue(world); + invokation = await invoke(world, cToken.methods.repayBorrowBehalf(behalf), from, CTokenErrorReporter); + } + + world = addAction( + world, + `CToken ${cToken.name}: ${describeUser(world, from)} repays ${showAmount} of borrow on behalf of ${describeUser(world, behalf)}`, + invokation + ); + + return world; +} + +async function liquidateBorrow(world: World, from: string, cToken: CToken, borrower: string, collateral: CToken, repayAmount: NumberV | NothingV): Promise { + let invokation; + let showAmount; + + if (repayAmount instanceof NumberV) { + showAmount = repayAmount.show(); + invokation = await invoke(world, cToken.methods.liquidateBorrow(borrower, repayAmount.encode(), collateral._address), from, CTokenErrorReporter); + } else { + showAmount = showTrxValue(world); + invokation = await invoke(world, cToken.methods.liquidateBorrow(borrower, collateral._address), from, CTokenErrorReporter); + } + + world = addAction( + world, + `CToken ${cToken.name}: ${describeUser(world, from)} liquidates ${showAmount} from of ${describeUser(world, borrower)}, seizing ${collateral.name}.`, + invokation + ); + + return world; +} + +async function seize(world: World, from: string, cToken: CToken, liquidator: string, borrower: string, seizeTokens: NumberV): Promise { + let invokation = await invoke(world, cToken.methods.seize(liquidator, borrower, seizeTokens.encode()), from, CTokenErrorReporter); + + world = addAction( + world, + `CToken ${cToken.name}: ${describeUser(world, from)} initiates seizing ${seizeTokens.show()} to ${describeUser(world, liquidator)} from ${describeUser(world, borrower)}.`, + invokation + ); + + return world; +} + +async function evilSeize(world: World, from: string, cToken: CToken, treasure: CToken, liquidator: string, borrower: string, seizeTokens: NumberV): Promise { + let invokation = await invoke(world, cToken.methods.evilSeize(treasure._address, liquidator, borrower, seizeTokens.encode()), from, CTokenErrorReporter); + + world = addAction( + world, + `CToken ${cToken.name}: ${describeUser(world, from)} initiates illegal seizing ${seizeTokens.show()} to ${describeUser(world, liquidator)} from ${describeUser(world, borrower)}.`, + invokation + ); + + return world; +} + +async function setPendingAdmin(world: World, from: string, cToken: CToken, newPendingAdmin: string): Promise { + let invokation = await invoke(world, cToken.methods._setPendingAdmin(newPendingAdmin), from, CTokenErrorReporter); + + world = addAction( + world, + `CToken ${cToken.name}: ${describeUser(world, from)} sets pending admin to ${newPendingAdmin}`, + invokation + ); + + return world; +} + +async function acceptAdmin(world: World, from: string, cToken: CToken): Promise { + let invokation = await invoke(world, cToken.methods._acceptAdmin(), from, CTokenErrorReporter); + + world = addAction( + world, + `CToken ${cToken.name}: ${describeUser(world, from)} accepts admin`, + invokation + ); + + return world; +} + +async function reduceReserves(world: World, from: string, cToken: CToken, amount: NumberV): Promise { + let invokation = await invoke(world, cToken.methods._reduceReserves(amount.encode()), from, CTokenErrorReporter); + + world = addAction( + world, + `CToken ${cToken.name}: ${describeUser(world, from)} reduces reserves by ${amount.show()}`, + invokation + ); + + return world; +} + +async function setReserveFactor(world: World, from: string, cToken: CToken, reserveFactor: NumberV): Promise { + let invokation = await invoke(world, cToken.methods._setReserveFactor(reserveFactor.encode()), from, CTokenErrorReporter); + + world = addAction( + world, + `CToken ${cToken.name}: ${describeUser(world, from)} sets reserve factor to ${reserveFactor.show()}`, + invokation + ); + + return world; +} + +async function setInterestRateModel(world: World, from: string, cToken: CToken, interestRateModel: string): Promise { + let invokation = await invoke(world, cToken.methods._setInterestRateModel(interestRateModel), from, CTokenErrorReporter); + + world = addAction( + world, + `Set interest rate for ${cToken.name} to ${interestRateModel} as ${describeUser(world, from)}`, + invokation + ); + + return world; +} + +async function setComptroller(world: World, from: string, cToken: CToken, comptroller: string): Promise { + let invokation = await invoke(world, cToken.methods._setComptroller(comptroller), from, CTokenErrorReporter); + + world = addAction( + world, + `Set comptroller for ${cToken.name} to ${comptroller} as ${describeUser(world, from)}`, + invokation + ); + + return world; +} + +async function donate(world: World, from: string, cToken: CToken): Promise { + let invokation = await invoke(world, cToken.methods.donate(), from, CTokenErrorReporter); + + world = addAction( + world, + `Donate for ${cToken.name} as ${describeUser(world, from)} with value ${showTrxValue(world)}`, + invokation + ); + + return world; +} + +async function setCTokenMock(world: World, from: string, cToken: CTokenScenario, mock: string, value: NumberV): Promise { + let mockMethod: (number) => Sendable; + + switch (mock.toLowerCase()) { + case "totalborrows": + mockMethod = cToken.methods.setTotalBorrows; + break; + case "totalreserves": + mockMethod = cToken.methods.setTotalReserves; + break; + default: + throw new Error(`Mock "${mock}" not defined for cToken`); + } + + let invokation = await invoke(world, mockMethod(value.encode()), from); + + world = addAction( + world, + `Mocked ${mock}=${value.show()} for ${cToken.name}`, + invokation + ); + + return world; +} + +async function verifyCToken(world: World, cToken: CToken, name: string, contract: string, apiKey: string): Promise { + if (world.isLocalNetwork()) { + world.printer.printLine(`Politely declining to verify on local network: ${world.network}.`); + } else { + await verify(world, apiKey, name, contract, cToken._address); + } + + return world; +} + +async function printMinters(world: World, cToken: CToken): Promise { + let events = await getPastEvents(world, cToken, cToken.name, 'Mint'); + let addresses = events.map((event) => event.returnValues['minter']); + let uniq = [...new Set(addresses)]; + + world.printer.printLine("Minters:") + + uniq.forEach((address) => { + world.printer.printLine(`\t${address}`) + }); + + return world; +} + +async function printBorrowers(world: World, cToken: CToken): Promise { + let events = await getPastEvents(world, cToken, cToken.name, 'Borrow'); + let addresses = events.map((event) => event.returnValues['borrower']); + let uniq = [...new Set(addresses)]; + + world.printer.printLine("Borrowers:") + + uniq.forEach((address) => { + world.printer.printLine(`\t${address}`) + }); + + return world; +} + +async function printLiquidity(world: World, cToken: CToken): Promise { + let mintEvents = await getPastEvents(world, cToken, cToken.name, 'Mint'); + let mintAddresses = mintEvents.map((event) => event.returnValues['minter']); + let borrowEvents = await getPastEvents(world, cToken, cToken.name, 'Borrow'); + let borrowAddresses = borrowEvents.map((event) => event.returnValues['borrower']); + let uniq = [...new Set(mintAddresses.concat(borrowAddresses))]; + let comptroller = await getComptroller(world); + + world.printer.printLine("Liquidity:") + + const liquidityMap = await Promise.all(uniq.map(async (address) => { + let userLiquidity = await getLiquidity(world, comptroller, address); + + return [address, userLiquidity.val]; + })); + + liquidityMap.forEach(([address, liquidity]) => { + world.printer.printLine(`\t${world.settings.lookupAlias(address)}: ${liquidity / 1e18}e18`) + }); + + return world; +} + +export function cTokenCommands() { + return [ + new Command<{cTokenParams: EventV}>(` + #### Deploy + + * "CToken Deploy ...cTokenParams" - Generates a new CToken + * E.g. "CToken cZRX Deploy" + `, + "Deploy", + [new Arg("cTokenParams", getEventV, {variadic: true})], + (world, from, {cTokenParams}) => genCToken(world, from, cTokenParams.val) + ), + new View<{cTokenArg: StringV, apiKey: StringV}>(` + #### Verify + + * "CToken Verify apiKey:" - Verifies CToken in Etherscan + * E.g. "CToken cZRX Verify "myApiKey" + `, + "Verify", + [ + new Arg("cTokenArg", getStringV), + new Arg("apiKey", getStringV) + ], + async (world, {cTokenArg, apiKey}) => { + let [cToken, name, data] = await getCTokenData(world, cTokenArg.val); + + return await verifyCToken(world, cToken, name, data.get('contract')!, apiKey.val); + }, + {namePos: 1} + ), + new Command<{cToken: CToken}>(` + #### AccrueInterest + + * "CToken AccrueInterest" - Accrues interest for given token + * E.g. "CToken cZRX AccrueInterest" + `, + "AccrueInterest", + [ + new Arg("cToken", getCTokenV) + ], + (world, from, {cToken}) => accrueInterest(world, from, cToken), + {namePos: 1} + ), + new Command<{cToken: CToken, amount: NumberV | NothingV}>(` + #### Mint + + * "CToken Mint amount:" - Mints the given amount of cToken as specified user + * E.g. "CToken cZRX Mint 1.0e18" + `, + "Mint", + [ + new Arg("cToken", getCTokenV), + new Arg("amount", getNumberV, {nullable: true}) + ], + (world, from, {cToken, amount}) => mint(world, from, cToken, amount), + {namePos: 1} + ), + new Command<{cToken: CToken, tokens: NumberV}>(` + #### Redeem + + * "CToken Redeem tokens:" - Redeems the given amount of cTokens as specified user + * E.g. "CToken cZRX Redeem 1.0e9" + `, + "Redeem", + [ + new Arg("cToken", getCTokenV), + new Arg("tokens", getNumberV) + ], + (world, from, {cToken, tokens}) => redeem(world, from, cToken, tokens), + {namePos: 1} + ), + new Command<{cToken: CToken, amount: NumberV}>(` + #### RedeemUnderlying + + * "CToken RedeemUnderlying amount:" - Redeems the given amount of underlying as specified user + * E.g. "CToken cZRX RedeemUnderlying 1.0e18" + `, + "RedeemUnderlying", + [ + new Arg("cToken", getCTokenV), + new Arg("amount", getNumberV) + ], + (world, from, {cToken, amount}) => redeemUnderlying(world, from, cToken, amount), + {namePos: 1} + ), + new Command<{cToken: CToken, amount: NumberV}>(` + #### Borrow + + * "CToken Borrow amount:" - Borrows the given amount of this cToken as specified user + * E.g. "CToken cZRX Borrow 1.0e18" + `, + "Borrow", + [ + new Arg("cToken", getCTokenV), + new Arg("amount", getNumberV) + ], + // Note: we override from + (world, from, {cToken, amount}) => borrow(world, from, cToken, amount), + {namePos: 1} + ), + new Command<{cToken: CToken, amount: NumberV | NothingV}>(` + #### RepayBorrow + + * "CToken RepayBorrow underlyingAmount:" - Repays borrow in the given underlying amount as specified user + * E.g. "CToken cZRX RepayBorrow 1.0e18" + `, + "RepayBorrow", + [ + new Arg("cToken", getCTokenV), + new Arg("amount", getNumberV, {nullable: true}) + ], + (world, from, {cToken, amount}) => repayBorrow(world, from, cToken, amount), + {namePos: 1} + ), + new Command<{cToken: CToken, behalf: AddressV, amount: NumberV | NothingV}>(` + #### RepayBorrowBehalf + + * "CToken RepayBorrowBehalf behalf: underlyingAmount:" - Repays borrow in the given underlying amount on behalf of another user + * E.g. "CToken cZRX RepayBorrowBehalf Geoff 1.0e18" + `, + "RepayBorrowBehalf", + [ + new Arg("cToken", getCTokenV), + new Arg("behalf", getAddressV), + new Arg("amount", getNumberV, {nullable: true}) + ], + (world, from, {cToken, behalf, amount}) => repayBorrowBehalf(world, from, behalf.val, cToken, amount), + {namePos: 1} + ), + new Command<{borrower: AddressV, cToken: CToken, collateral: CToken, repayAmount: NumberV | NothingV}>(` + #### Liquidate + + * "CToken Liquidate borrower: cTokenCollateral:
repayAmount:" - Liquidates repayAmount of given token seizing collateral token + * E.g. "CToken cZRX Liquidate Geoff cBAT 1.0e18" + `, + "Liquidate", + [ + new Arg("cToken", getCTokenV), + new Arg("borrower", getAddressV), + new Arg("collateral", getCTokenV), + new Arg("repayAmount", getNumberV, {nullable: true}) + ], + (world, from, {borrower, cToken, collateral, repayAmount}) => liquidateBorrow(world, from, cToken, borrower.val, collateral, repayAmount), + {namePos: 1} + ), + new Command<{cToken: CToken, liquidator: AddressV, borrower: AddressV, seizeTokens: NumberV}>(` + #### Seize + + * "CToken Seize liquidator: borrower: seizeTokens:" - Seizes a given number of tokens from a user (to be called from other CToken) + * E.g. "CToken cZRX Seize Geoff Torrey 1.0e18" + `, + "Seize", + [ + new Arg("cToken", getCTokenV), + new Arg("liquidator", getAddressV), + new Arg("borrower", getAddressV), + new Arg("seizeTokens", getNumberV) + ], + (world, from, {cToken, liquidator, borrower, seizeTokens}) => seize(world, from, cToken, liquidator.val, borrower.val, seizeTokens), + {namePos: 1} + ), + new Command<{cToken: CToken, treasure: CToken, liquidator: AddressV, borrower: AddressV, seizeTokens: NumberV}>(` + #### EvilSeize + + * "CToken EvilSeize treasure: liquidator: borrower: seizeTokens:" - Improperly seizes a given number of tokens from a user + * E.g. "CToken cEVL EvilSeize cZRX Geoff Torrey 1.0e18" + `, + "EvilSeize", + [ + new Arg("cToken", getCTokenV), + new Arg("treasure", getCTokenV), + new Arg("liquidator", getAddressV), + new Arg("borrower", getAddressV), + new Arg("seizeTokens", getNumberV) + ], + (world, from, {cToken, treasure, liquidator, borrower, seizeTokens}) => evilSeize(world, from, cToken, treasure, liquidator.val, borrower.val, seizeTokens), + {namePos: 1} + ), + new Command<{cToken: CToken, amount: NumberV}>(` + #### ReduceReserves + + * "CToken ReduceReserves amount:" - Reduces the reserves of the cToken + * E.g. "CToken cZRX ReduceReserves 1.0e18" + `, + "ReduceReserves", + [ + new Arg("cToken", getCTokenV), + new Arg("amount", getNumberV) + ], + (world, from, {cToken, amount}) => reduceReserves(world, from, cToken, amount), + {namePos: 1} + ), + new Command<{cToken: CToken, newPendingAdmin: AddressV}>(` + #### SetPendingAdmin + + * "CToken SetPendingAdmin newPendingAdmin:
" - Sets the pending admin for the cToken + * E.g. "CToken cZRX SetPendingAdmin Geoff" + `, + "SetPendingAdmin", + [ + new Arg("cToken", getCTokenV), + new Arg("newPendingAdmin", getAddressV) + ], + (world, from, {cToken, newPendingAdmin}) => setPendingAdmin(world, from, cToken, newPendingAdmin.val), + {namePos: 1} + ), + new Command<{cToken: CToken}>(` + #### AcceptAdmin + + * "CToken AcceptAdmin" - Accepts admin for the cToken + * E.g. "From Geoff (CToken cZRX AcceptAdmin)" + `, + "AcceptAdmin", + [ + new Arg("cToken", getCTokenV) + ], + (world, from, {cToken}) => acceptAdmin(world, from, cToken), + {namePos: 1} + ), + new Command<{cToken: CToken, reserveFactor: NumberV}>(` + #### SetReserveFactor + + * "CToken SetReserveFactor reserveFactor:" - Sets the reserve factor for the cToken + * E.g. "CToken cZRX SetReserveFactor 0.1" + `, + "SetReserveFactor", + [ + new Arg("cToken", getCTokenV), + new Arg("reserveFactor", getExpNumberV) + ], + (world, from, {cToken, reserveFactor}) => setReserveFactor(world, from, cToken, reserveFactor), + {namePos: 1} + ), + new Command<{cToken: CToken, interestRateModel: AddressV}>(` + #### SetInterestRateModel + + * "CToken SetInterestRateModel interestRateModel:" - Sets the interest rate model for the given cToken + * E.g. "CToken cZRX SetInterestRateModel (FixedRate 1.5)" + `, + "SetInterestRateModel", + [ + new Arg("cToken", getCTokenV), + new Arg("interestRateModel", getAddressV) + ], + (world, from, {cToken, interestRateModel}) => setInterestRateModel(world, from, cToken, interestRateModel.val), + {namePos: 1} + ), + new Command<{cToken: CToken, comptroller: AddressV}>(` + #### SetComptroller + + * "CToken SetComptroller comptroller:" - Sets the comptroller for the given cToken + * E.g. "CToken cZRX SetComptroller Comptroller" + `, + "SetComptroller", + [ + new Arg("cToken", getCTokenV), + new Arg("comptroller", getAddressV) + ], + (world, from, {cToken, comptroller}) => setComptroller(world, from, cToken, comptroller.val), + {namePos: 1} + ), + new Command<{cToken: CToken}>(` + #### Donate + + * "CToken Donate" - Calls the donate (payable no-op) function + * E.g. "(Trx Value 5.0e18 (CToken cETH Donate))" + `, + "Donate", + [ + new Arg("cToken", getCTokenV) + ], + (world, from, {cToken}) => donate(world, from, cToken), + {namePos: 1} + ), + new Command<{cToken: CToken, variable: StringV, value: NumberV}>(` + #### Mock + + * "CToken Mock variable: value:" - Mocks a given value on cToken. Note: value must be a supported mock and this will only work on a "CTokenScenario" contract. + * E.g. "CToken cZRX Mock totalBorrows 5.0e18" + * E.g. "CToken cZRX Mock totalReserves 0.5e18" + `, + "Mock", + [ + new Arg("cToken", getCTokenV), + new Arg("variable", getStringV), + new Arg("value", getNumberV), + ], + (world, from, {cToken, variable, value}) => setCTokenMock(world, from, cToken, variable.val, value), + {namePos: 1} + ), + new View<{cToken: CToken}>(` + #### Minters + + * "CToken Minters" - Print address of all minters + `, + "Minters", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => printMinters(world, cToken), + {namePos: 1} + ), + new View<{cToken: CToken}>(` + #### Borrowers + + * "CToken Borrowers" - Print address of all borrowers + `, + "Borrowers", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => printBorrowers(world, cToken), + {namePos: 1} + ), + new View<{cToken: CToken}>(` + #### Liquidity + + * "CToken Liquidity" - Prints liquidity of all minters or borrowers + `, + "Liquidity", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => printLiquidity(world, cToken), + {namePos: 1} + ), + new View<{cToken: CToken, input: StringV}>(` + #### Decode + + * "Decode input:" - Prints information about a call to a cToken contract + `, + "Decode", + [ + new Arg("cToken", getCTokenV), + new Arg("input", getStringV) + + ], + (world, {cToken, input}) => decodeCall(world, cToken, input.val), + {namePos: 1} + ) + ]; +} + +export async function processCTokenEvent(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("CToken", cTokenCommands(), world, event, from); +} diff --git a/scenario/src/Event/ComptrollerEvent.ts b/scenario/src/Event/ComptrollerEvent.ts new file mode 100644 index 000000000..438bc7be6 --- /dev/null +++ b/scenario/src/Event/ComptrollerEvent.ts @@ -0,0 +1,447 @@ +import {Event} from '../Event'; +import {addAction, describeUser, World} from '../World'; +import {decodeCall, getPastEvents} from '../Contract'; +import {Comptroller} from '../Contract/Comptroller'; +import {ComptrollerImpl} from '../Contract/ComptrollerImpl'; +import {CToken} from '../Contract/CToken'; +import {invoke} from '../Invokation'; +import { + getAddressV, + getBoolV, + getEventV, + getExpNumberV, + getNumberV, + getPercentV, + getStringV +} from '../CoreValue'; +import { + AddressV, + BoolV, + EventV, + NumberV, + StringV +} from '../Value'; +import {Arg, Command, View, processCommandEvent} from '../Command'; +import {buildComptrollerImpl} from '../Builder/ComptrollerImplBuilder'; +import {ComptrollerErrorReporter} from '../ErrorReporter'; +import {getComptroller, getComptrollerImpl} from '../ContractLookup'; +import {getLiquidity} from '../Value/ComptrollerValue'; +import {getCTokenV} from '../Value/CTokenValue'; +import {encodedNumber} from '../Encoding'; + +async function genComptroller(world: World, from: string, params: Event): Promise { + let {world: nextWorld, comptrollerImpl: comptroller, comptrollerImplData: comptrollerData} = await buildComptrollerImpl(world, from, params); + world = nextWorld; + + world = addAction( + world, + `Added Comptroller (${comptrollerData.description}) at address ${comptroller._address}`, + comptrollerData.invokation + ); + + return world; +}; + +async function setPaused(world: World, from: string, comptroller: Comptroller, actionName: string, isPaused: boolean): Promise { + const pauseMap = { + "Mint": comptroller.methods._setMintPaused + }; + + if (!pauseMap[actionName]) { + throw `Cannot find pause function for action "${actionName}"`; + } + + let invokation = await invoke(world, comptroller[actionName]([isPaused]), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Comptroller: set paused for ${actionName} to ${isPaused}`, + invokation + ); + + return world; +} + +async function setMaxAssets(world: World, from: string, comptroller: Comptroller, numberOfAssets: NumberV): Promise { + let invokation = await invoke(world, comptroller.methods._setMaxAssets(numberOfAssets.encode()), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Set max assets to ${numberOfAssets.show()}`, + invokation + ); + + return world; +} + +async function setLiquidationIncentive(world: World, from: string, comptroller: Comptroller, liquidationIncentive: NumberV): Promise { + let invokation = await invoke(world, comptroller.methods._setLiquidationIncentive(liquidationIncentive.encode()), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Set liquidation incentive to ${liquidationIncentive.show()}`, + invokation + ); + + return world; +} + +async function supportMarket(world: World, from: string, comptroller: Comptroller, cToken: CToken): Promise { + if (world.dryRun) { + // Skip this specifically on dry runs since it's likely to crash due to a number of reasons + world.printer.printLine(`Dry run: Supporting market \`${cToken._address}\``); + return world; + } + + let invokation = await invoke(world, comptroller.methods._supportMarket(cToken._address), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Supported market ${cToken.name}`, + invokation + ); + + return world; +} + +async function unlistMarket(world: World, from: string, comptroller: Comptroller, cToken: CToken): Promise { + let invokation = await invoke(world, comptroller.methods.unlist(cToken._address), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Unlisted market ${cToken.name}`, + invokation + ); + + return world; +} + +async function enterMarkets(world: World, from: string, comptroller: Comptroller, assets: string[]): Promise { + let invokation = await invoke(world, comptroller.methods.enterMarkets(assets), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Called enter assets ${assets} as ${describeUser(world, from)}`, + invokation + ); + + return world; +} + +async function exitMarket(world: World, from: string, comptroller: Comptroller, asset: string): Promise { + let invokation = await invoke(world, comptroller.methods.exitMarket(asset), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Called exit market ${asset} as ${describeUser(world, from)}`, + invokation + ); + + return world; +} + +async function setPriceOracle(world: World, from: string, comptroller: Comptroller, priceOracleAddr: string): Promise { + let invokation = await invoke(world, comptroller.methods._setPriceOracle(priceOracleAddr), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Set price oracle for to ${priceOracleAddr} as ${describeUser(world, from)}`, + invokation + ); + + return world; +} + +async function setCollateralFactor(world: World, from: string, comptroller: Comptroller, cToken: CToken, collateralFactor: NumberV): Promise { + let invokation = await invoke(world, comptroller.methods._setCollateralFactor(cToken._address, collateralFactor.encode()), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Set collateral factor for ${cToken.name} to ${collateralFactor.show()}`, + invokation + ); + + return world; +} + +async function setCloseFactor(world: World, from: string, comptroller: Comptroller, closeFactor: NumberV): Promise { + let invokation = await invoke(world, comptroller.methods._setCloseFactor(closeFactor.encode()), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Set close factor to ${closeFactor.show()}`, + invokation + ); + + return world; +} + +async function fastForward(world: World, from: string, comptroller: Comptroller, blocks: NumberV): Promise { + let invokation = await invoke(world, comptroller.methods.fastForward(blocks.encode()), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Fast forward ${blocks.show()} blocks to #${invokation.value}`, + invokation + ); + + return world; +} + +async function printLiquidity(world: World, comptroller: Comptroller): Promise { + let enterEvents = await getPastEvents(world, comptroller, 'StdComptroller', 'MarketEntered'); + let addresses = enterEvents.map((event) => event.returnValues['account']); + let uniq = [...new Set(addresses)]; + + world.printer.printLine("Liquidity:") + + const liquidityMap = await Promise.all(uniq.map(async (address) => { + let userLiquidity = await getLiquidity(world, comptroller, address); + + return [address, userLiquidity.val]; + })); + + liquidityMap.forEach(([address, liquidity]) => { + world.printer.printLine(`\t${world.settings.lookupAlias(address)}: ${liquidity / 1e18}e18`) + }); + + return world; +} + +async function setPendingAdmin(world: World, from: string, comptroller: Comptroller, newPendingAdmin: string): Promise { + let invokation = await invoke(world, comptroller.methods._setPendingAdmin(newPendingAdmin), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Comptroller: ${describeUser(world, from)} sets pending admin to ${newPendingAdmin}`, + invokation + ); + + return world; +} + +async function acceptAdmin(world: World, from: string, comptroller: Comptroller): Promise { + let invokation = await invoke(world, comptroller.methods._acceptAdmin(), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Comptroller: ${describeUser(world, from)} accepts admin`, + invokation + ); + + return world; +} + +export function comptrollerCommands() { + return [ + new Command<{comptrollerParams: EventV}>(` + #### Deploy + + * "Comptroller Deploy ...comptrollerParams" - Generates a new Comptroller (not as Impl) + * E.g. "Comptroller Deploy YesNo" + `, + "Deploy", + [new Arg("comptrollerParams", getEventV, {variadic: true})], + (world, from, {comptrollerParams}) => genComptroller(world, from, comptrollerParams.val) + ), + new Command<{comptroller: Comptroller, action: StringV, isPaused: BoolV}>(` + #### SetPaused + + * "Comptroller SetPaused " - Pauses or unpaused given cToken function + * E.g. "Comptroller SetPaused "Mint" True" + `, + "SetPaused", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("action", getStringV), + new Arg("isPaused", getBoolV) + ], + (world, from, {comptroller, action, isPaused}) => setPaused(world, from, comptroller, action.val, isPaused.val) + ), + new Command<{comptroller: Comptroller, cToken: CToken}>(` + #### SupportMarket + + * "Comptroller SupportMarket " - Adds support in the Comptroller for the given cToken + * E.g. "Comptroller SupportMarket cZRX" + `, + "SupportMarket", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("cToken", getCTokenV) + ], + (world, from, {comptroller, cToken}) => supportMarket(world, from, comptroller, cToken) + ), + new Command<{comptroller: Comptroller, cToken: CToken}>(` + #### UnList + + * "Comptroller UnList " - Mock unlists a given market in tests + * E.g. "Comptroller UnList cZRX" + `, + "UnList", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("cToken", getCTokenV) + ], + (world, from, {comptroller, cToken}) => unlistMarket(world, from, comptroller, cToken) + ), + new Command<{comptroller: Comptroller, cTokens: CToken[]}>(` + #### EnterMarkets + + * "Comptroller EnterMarkets ( ...)" - User enters the given markets + * E.g. "Comptroller EnterMarkets (cZRX cETH)" + `, + "EnterMarkets", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("cTokens", getCTokenV, {mapped: true}) + ], + (world, from, {comptroller, cTokens}) => enterMarkets(world, from, comptroller, cTokens.map((c) => c._address)) + ), + new Command<{comptroller: Comptroller, cToken: CToken}>(` + #### ExitMarket + + * "Comptroller ExitMarket " - User exits the given markets + * E.g. "Comptroller ExitMarket cZRX" + `, + "ExitMarket", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("cToken", getCTokenV) + ], + (world, from, {comptroller, cToken}) => exitMarket(world, from, comptroller, cToken._address) + ), + new Command<{comptroller: Comptroller, maxAssets: NumberV}>(` + #### SetMaxAssets + + * "Comptroller SetMaxAssets " - Sets (or resets) the max allowed asset count + * E.g. "Comptroller SetMaxAssets 4" + `, + "SetMaxAssets", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("maxAssets", getNumberV) + ], + (world, from, {comptroller, maxAssets}) => setMaxAssets(world, from, comptroller, maxAssets) + ), + new Command<{comptroller: Comptroller, liquidationIncentive: NumberV}>(` + #### LiquidationIncentive + + * "Comptroller LiquidationIncentive " - Sets the liquidation incentive + * E.g. "Comptroller LiquidationIncentive 1.1" + `, + "LiquidationIncentive", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("liquidationIncentive", getExpNumberV) + ], + (world, from, {comptroller, liquidationIncentive}) => setLiquidationIncentive(world, from, comptroller, liquidationIncentive) + ), + new Command<{comptroller: Comptroller, priceOracle: AddressV}>(` + #### SetPriceOracle + + * "Comptroller SetPriceOracle oracle:
" - Sets the price oracle address + * E.g. "Comptroller SetPriceOracle 0x..." + `, + "SetPriceOracle", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("priceOracle", getAddressV) + ], + (world, from, {comptroller, priceOracle}) => setPriceOracle(world, from, comptroller, priceOracle.val) + ), + new Command<{comptroller: Comptroller, cToken: CToken, collateralFactor: NumberV}>(` + #### SetCollateralFactor + + * "Comptroller SetCollateralFactor " - Sets the collateral factor for given cToken to number + * E.g. "Comptroller SetCollateralFactor cZRX 0.1" + `, + "SetCollateralFactor", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("cToken", getCTokenV), + new Arg("collateralFactor", getExpNumberV) + ], + (world, from, {comptroller, cToken, collateralFactor}) => setCollateralFactor(world, from, comptroller, cToken, collateralFactor) + ), + new Command<{comptroller: Comptroller, closeFactor: NumberV}>(` + #### SetCloseFactor + + * "Comptroller SetCloseFactor " - Sets the close factor to given percentage + * E.g. "Comptroller SetCloseFactor 0.2" + `, + "SetCloseFactor", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("closeFactor", getPercentV) + ], + (world, from, {comptroller, closeFactor}) => setCloseFactor(world, from, comptroller, closeFactor) + ), + new Command<{comptroller: Comptroller, newPendingAdmin: AddressV}>(` + #### SetPendingAdmin + + * "Comptroller SetPendingAdmin newPendingAdmin:
" - Sets the pending admin for the Comptroller + * E.g. "Comptroller SetPendingAdmin Geoff" + `, + "SetPendingAdmin", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("newPendingAdmin", getAddressV) + ], + (world, from, {comptroller, newPendingAdmin}) => setPendingAdmin(world, from, comptroller, newPendingAdmin.val) + ), + new Command<{comptroller: Comptroller}>(` + #### AcceptAdmin + + * "Comptroller AcceptAdmin" - Accepts admin for the Comptroller + * E.g. "From Geoff (Comptroller AcceptAdmin)" + `, + "AcceptAdmin", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + ], + (world, from, {comptroller}) => acceptAdmin(world, from, comptroller) + ), + new Command<{comptroller: Comptroller, blocks: NumberV, _keyword: StringV}>(` + #### FastForward + + * "FastForward n: Blocks" - Moves the block number forward "n" blocks. Note: in "CTokenScenario" and "ComptrollerScenario" the current block number is mocked (starting at 100000). This is the only way for the protocol to see a higher block number (for accruing interest). + * E.g. "Comptroller FastForward 5 Blocks" - Move block number forward 5 blocks. + `, + "FastForward", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("blocks", getNumberV), + new Arg("_keyword", getStringV) + ], + (world, from, {comptroller, blocks}) => fastForward(world, from, comptroller, blocks) + ), + new View<{comptroller: Comptroller}>(` + #### Liquidity + + * "Comptroller Liquidity" - Prints liquidity of all minters or borrowers + `, + "Liquidity", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + ], + (world, {comptroller}) => printLiquidity(world, comptroller) + ), + new View<{comptroller: Comptroller, input: StringV}>(` + #### Decode + + * "Decode input:" - Prints information about a call to a Comptroller contract + `, + "Decode", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("input", getStringV) + + ], + (world, {comptroller, input}) => decodeCall(world, comptroller, input.val) + ) + ]; +} + +export async function processComptrollerEvent(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("Comptroller", comptrollerCommands(), world, event, from); +} diff --git a/scenario/src/Event/ComptrollerImplEvent.ts b/scenario/src/Event/ComptrollerImplEvent.ts new file mode 100644 index 000000000..c7222fd24 --- /dev/null +++ b/scenario/src/Event/ComptrollerImplEvent.ts @@ -0,0 +1,147 @@ +import {Event} from '../Event'; +import {addAction, describeUser, World} from '../World'; +import {ComptrollerImpl} from '../Contract/ComptrollerImpl'; +import {Unitroller} from '../Contract/Unitroller'; +import {invoke} from '../Invokation'; +import { + getAddressV, + getEventV, + getExpNumberV, + getNumberV, + getStringV +} from '../CoreValue'; +import { + AddressV, + EventV, + NumberV, + StringV +} from '../Value'; +import {Arg, Command, View, processCommandEvent} from '../Command'; +import {buildComptrollerImpl} from '../Builder/ComptrollerImplBuilder'; +import {ComptrollerErrorReporter} from '../ErrorReporter'; +import {getComptrollerImpl, getComptrollerImplData, getUnitroller} from '../ContractLookup'; +import {verify} from '../Verify'; +import {mergeContractABI} from '../Networks'; +import {encodedNumber} from '../Encoding'; + +async function genComptrollerImpl(world: World, from: string, params: Event): Promise { + let {world: nextWorld, comptrollerImpl, comptrollerImplData} = await buildComptrollerImpl(world, from, params); + world = nextWorld; + + world = addAction( + world, + `Added Comptroller Implementation (${comptrollerImplData.description}) at address ${comptrollerImpl._address}`, + comptrollerImplData.invokation + ); + + return world; +}; + +async function become(world: World, from: string, comptrollerImpl: ComptrollerImpl, unitroller: Unitroller, priceOracleAddr: string, closeFactor: encodedNumber, maxAssets: encodedNumber): Promise { + let invokation = await invoke(world, comptrollerImpl.methods._become(unitroller._address, priceOracleAddr, closeFactor, maxAssets, false), from, ComptrollerErrorReporter); + + if (!world.dryRun) { + // Skip this specifically on dry runs since it's likely to crash due to a number of reasons + world = await mergeContractABI(world, 'Comptroller', unitroller, unitroller.name, comptrollerImpl.name); + } + + world = addAction( + world, + `Become ${unitroller._address}'s Comptroller Impl with priceOracle=${priceOracleAddr},closeFactor=${closeFactor},maxAssets=${maxAssets}`, + invokation + ); + + return world; +} + +async function recome(world: World, from: string, comptrollerImpl: ComptrollerImpl, unitroller: Unitroller): Promise { + let invokation = await invoke(world, comptrollerImpl.methods._become(unitroller._address, "0x0000000000000000000000000000000000000000", 0, 0, true), from, ComptrollerErrorReporter); + + world = await mergeContractABI(world, 'Comptroller', unitroller, unitroller.name, comptrollerImpl.name); + + world = addAction( + world, + `Recome ${unitroller._address}'s Comptroller Impl`, + invokation + ); + + return world; +} + +async function verifyComptrollerImpl(world: World, comptrollerImpl: ComptrollerImpl, name: string, contract: string, apiKey: string): Promise { + if (world.isLocalNetwork()) { + world.printer.printLine(`Politely declining to verify on local network: ${world.network}.`); + } else { + await verify(world, apiKey, name, contract, comptrollerImpl._address); + } + + return world; +} + +export function comptrollerImplCommands() { + return [ + new Command<{comptrollerImplParams: EventV}>(` + #### Deploy + + * "ComptrollerImpl Deploy ...comptrollerImplParams" - Generates a new Comptroller Implementation + * E.g. "ComptrollerImpl Deploy MyScen Scenario" + `, + "Deploy", + [new Arg("comptrollerImplParams", getEventV, {variadic: true})], + (world, from, {comptrollerImplParams}) => genComptrollerImpl(world, from, comptrollerImplParams.val) + ), + new View<{comptrollerImplArg: StringV, apiKey: StringV}>(` + #### Verify + + * "ComptrollerImpl Verify apiKey:" - Verifies Comptroller Implemetation in Etherscan + * E.g. "ComptrollerImpl Verify "myApiKey" + `, + "Verify", + [ + new Arg("comptrollerImplArg", getStringV), + new Arg("apiKey", getStringV) + ], + async (world, {comptrollerImplArg, apiKey}) => { + let [comptrollerImpl, name, data] = await getComptrollerImplData(world, comptrollerImplArg.val); + + return await verifyComptrollerImpl(world, comptrollerImpl, name, data.get('contract')!, apiKey.val); + }, + {namePos: 1} + ), + new Command<{unitroller: Unitroller, comptrollerImpl: ComptrollerImpl, priceOracle: AddressV, closeFactor: NumberV, maxAssets: NumberV}>(` + #### Become + + * "ComptrollerImpl Become priceOracle: closeFactor: maxAssets:" - Become the comptroller, if possible. + * E.g. "ComptrollerImpl MyImpl Become + `, + "Become", + [ + new Arg("unitroller", getUnitroller, {implicit: true}), + new Arg("comptrollerImpl", getComptrollerImpl), + new Arg("priceOracle", getAddressV), + new Arg("closeFactor", getExpNumberV), + new Arg("maxAssets", getNumberV) + ], + (world, from, {unitroller, comptrollerImpl, priceOracle, closeFactor, maxAssets}) => become(world, from, comptrollerImpl, unitroller, priceOracle.val, closeFactor.encode(), maxAssets.encode()), + {namePos: 1} + ), + new Command<{unitroller: Unitroller, comptrollerImpl: ComptrollerImpl}>(` + #### Recome + + * "ComptrollerImpl Recome" - Recome the comptroller + * E.g. "ComptrollerImpl MyImpl Recome + `, + "Recome", + [ + new Arg("unitroller", getUnitroller, {implicit: true}), + new Arg("comptrollerImpl", getComptrollerImpl) + ], + (world, from, {unitroller, comptrollerImpl}) => recome(world, from, comptrollerImpl, unitroller), + {namePos: 1} + ) + ]; +} + +export async function processComptrollerImplEvent(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("ComptrollerImpl", comptrollerImplCommands(), world, event, from); +} diff --git a/scenario/src/Event/Erc20Event.ts b/scenario/src/Event/Erc20Event.ts new file mode 100644 index 000000000..0de272c0f --- /dev/null +++ b/scenario/src/Event/Erc20Event.ts @@ -0,0 +1,251 @@ +import {Event} from '../Event'; +import {addAction, World} from '../World'; +import {Erc20} from '../Contract/Erc20'; +import {invoke} from '../Invokation'; +import {buildErc20} from '../Builder/Erc20Builder'; +import { + getAddressV, + getBoolV, + getEventV, + getNumberV, + getStringV +} from '../CoreValue'; +import { + AddressV, + BoolV, + EventV, + NumberV, + StringV} from '../Value'; +import {getErc20V} from '../Value/Erc20Value'; +import {verify} from '../Verify'; +import {Arg, Command, View, processCommandEvent} from '../Command'; +import {CTokenErrorReporter} from '../ErrorReporter'; +import {encodedNumber} from '../Encoding'; +import {getErc20Data} from '../ContractLookup'; + +async function genToken(world: World, from: string, params: Event): Promise { + let {world: newWorld, erc20, tokenData} = await buildErc20(world, from, params); + world = newWorld; + + world = addAction( + world, + `Added ERC-20 token ${tokenData.symbol} (${tokenData.description}) at address ${erc20._address}`, + tokenData.invokation + ); + + return world; +} + +async function verifyErc20(world: World, erc20: Erc20, name: string, contract: string, apiKey: string): Promise { + if (world.isLocalNetwork()) { + world.printer.printLine(`Politely declining to verify on local network: ${world.network}.`); + } else { + await verify(world, apiKey, name, contract, erc20._address); + } + + return world; +} + +async function approve(world: World, from: string, erc20: Erc20, address: string, amount: NumberV): Promise { + let invokation = await invoke(world, erc20.methods.approve(address, amount.encode()), from, CTokenErrorReporter); + + world = addAction( + world, + `Approved ${erc20.name} ERC-20 token for ${from} of ${amount.show()}`, + invokation + ); + + return world; +} + +async function faucet(world: World, from: string, erc20: Erc20, address: string, amount: NumberV): Promise { + let invokation = await invoke(world, erc20.methods.allocateTo(address, amount.encode()), from, CTokenErrorReporter); + + world = addAction( + world, + `Fauceted ${amount.show()} ERC-20 tokens to ${address}`, + invokation + ); + + return world; +} + +async function transfer(world: World, from: string, erc20: Erc20, address: string, amount: NumberV): Promise { + let invokation = await invoke(world, erc20.methods.transfer(address, amount.encode()), from, CTokenErrorReporter); + + world = addAction( + world, + `Transferred ${amount.show()} ERC-20 tokens from ${from} to ${address}`, + invokation + ); + + return world; +} + +async function transferFrom(world: World, from: string, erc20: Erc20, owner: string, spender: string, amount: NumberV): Promise { + let invokation = await invoke(world, erc20.methods.transferFrom(owner, spender, amount.encode()), from, CTokenErrorReporter); + + world = addAction( + world, + `"Transferred from" ${amount.show()} ERC-20 tokens from ${owner} to ${spender}`, + invokation + ); + + return world; +} + +async function setFail(world: World, from: string, erc20: Erc20, fail: boolean): Promise { + let invokation = await invoke(world, erc20.methods.setFail(fail), from, CTokenErrorReporter); + + world = addAction( + world, + `Set fail for ${erc20.name} to ${fail}`, + invokation + ); + + return world; +} + +async function setPaused(world: World, from: string, erc20: Erc20, pause: boolean): Promise { + let method = pause ? erc20.methods.pause() : erc20.methods.unpause(); + let invokation = await invoke(world, method, from); + + world = addAction( + world, + `Set ${erc20.name} ${pause ? 'paused' : 'unpaused'}`, + invokation + ); + + return world; +} + +export function erc20Commands() { + return [ + new Command<{erc20Params: EventV}>(` + #### Deploy + + * "Erc20 Deploy ...erc20Params" - Generates a new ERC-20 token by name + * E.g. "Erc20 ZRX Deploy" + `, + "Deploy", + [new Arg("erc20Params", getEventV, {variadic: true})], + (world, from, {erc20Params}) => genToken(world, from, erc20Params.val) + ), + new View<{erc20Arg: StringV, apiKey: StringV}>(` + #### Verify + + * "Erc20 Verify apiKey:" - Verifies Erc20 in Etherscan + * E.g. "Erc20 ZRX Verify "myApiKey" + `, + "Verify", + [ + new Arg("erc20Arg", getStringV), + new Arg("apiKey", getStringV) + ], + async (world, {erc20Arg, apiKey}) => { + console.log([erc20Arg, apiKey]); + let [erc20, name, data] = await getErc20Data(world, erc20Arg.val); + console.log([erc20, name, data.toJS()]); + + return await verifyErc20(world, erc20, name, data.get('contract')!, apiKey.val); + }, + {namePos: 1} + ), + new Command<{erc20: Erc20, spender: AddressV, amount: NumberV}>(` + #### Approve + + * "Erc20 Approve spender:
" - Adds an allowance between user and address + * E.g. "Erc20 ZRX Approve cZRX 1.0e18" + `, + "Approve", + [ + new Arg("erc20", getErc20V), + new Arg("spender", getAddressV), + new Arg("amount", getNumberV) + ], + (world, from, {erc20, spender, amount}) => approve(world, from, erc20, spender.val, amount), + {namePos: 1} + ), + new Command<{erc20: Erc20, recipient: AddressV, amount: NumberV}>(` + #### Faucet + + * "Erc20 Faucet recipient: " - Adds an arbitrary balance to given user + * E.g. "Erc20 ZRX Faucet Geoff 1.0e18" + `, + "Faucet", + [ + new Arg("erc20", getErc20V), + new Arg("recipient", getAddressV), + new Arg("amount", getNumberV) + ], + (world, from, {erc20, recipient, amount}) => { + return faucet(world, from, erc20, recipient.val, amount) + }, + {namePos: 1} + ), + new Command<{erc20: Erc20, recipient: AddressV, amount: NumberV}>(` + #### Transfer + + * "Erc20 Transfer recipient: " - Transfers a number of tokens via "transfer" as given user to recipient (this does not depend on allowance) + * E.g. "Erc20 ZRX Transfer Torrey 1.0e18" + `, + "Transfer", + [ + new Arg("erc20", getErc20V), + new Arg("recipient", getAddressV), + new Arg("amount", getNumberV) + ], + (world, from, {erc20, recipient, amount}) => transfer(world, from, erc20, recipient.val, amount), + {namePos: 1} + ), + new Command<{erc20: Erc20, owner: AddressV, spender: AddressV, amount: NumberV}>(` + #### TransferFrom + + * "Erc20 TransferFrom owner: spender: " - Transfers a number of tokens via "transfeFrom" to recipient (this depends on allowances) + * E.g. "Erc20 ZRX TransferFrom Geoff Torrey 1.0e18" + `, + "TransferFrom", + [ + new Arg("erc20", getErc20V), + new Arg("owner", getAddressV), + new Arg("spender", getAddressV), + new Arg("amount", getNumberV) + ], + (world, from, {erc20, owner, spender, amount}) => transferFrom(world, from, erc20, owner.val, spender.val, amount), + {namePos: 1} + ), + new Command<{erc20: Erc20, fail: BoolV}>(` + #### SetFail + + * "Erc20 SetFail fail:" - Sets failure on or off for an EvilToken + * E.g. "Erc20 EVL SetFail False" + `, + "SetFail", + [ + new Arg("erc20", getErc20V), + new Arg("fail", getBoolV) + ], + (world, from, {erc20, fail}) => setFail(world, from, erc20, fail.val), + {namePos: 1} + ), + new Command<{erc20: Erc20, paused: BoolV}>(` + #### Pause + + * "Erc20 Pause paused:" - Sets paused on or off for WBTC + * E.g. "Erc20 WBTC Pause" + * E.g. "Erc20 WBTC Pause False" + `, + "Pause", + [ + new Arg("erc20", getErc20V), + new Arg("paused", getBoolV, {default: new BoolV(true)}) + ], + (world, from, {erc20, paused}) => setPaused(world, from, erc20, paused.val), + {namePos: 1} + ) + ]; +} + +export async function processErc20Event(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("Erc20", erc20Commands(), world, event, from); +} diff --git a/scenario/src/Event/ExpectationEvent.ts b/scenario/src/Event/ExpectationEvent.ts new file mode 100644 index 000000000..0ee787a5a --- /dev/null +++ b/scenario/src/Event/ExpectationEvent.ts @@ -0,0 +1,68 @@ +import {Event} from '../Event'; +import {addExpectation, World} from '../World'; +import { + EventV, + NumberV, + Value +} from '../Value'; +import { + getCoreValue, + getEventV, + getNumberV +} from '../CoreValue'; +import {Invariant} from '../Invariant'; +import {ChangesExpectation} from '../Expectation/ChangesExpectation'; +import {RemainsExpectation} from '../Expectation/RemainsExpectation'; +import {formatEvent} from '../Formatter'; +import {Arg, View, processCommandEvent} from '../Command'; + +async function changesExpectation(world: World, condition: Event, delta: Value): Promise { + const value = await getCoreValue(world, condition); + const expectation = new ChangesExpectation(condition, value, delta); + + return addExpectation(world, expectation); +} + +async function remainsExpectation(world: World, condition: Event, value: Value): Promise { + const expectation = new RemainsExpectation(condition, value); + + // Immediately check value matches + await expectation.checker(world, true); + + return addExpectation(world, expectation); +} + +export function expectationCommands() { + return [ + new View<{condition: EventV, delta: NumberV}>(` + #### Changes + + * "Changes amount:" - Expects that given value changes by amount + * E.g ."Expect Changes (CToken cZRX UnderlyingBalance Geoff) +10e18" + `, + "Changes", + [ + new Arg("condition", getEventV), + new Arg("delta", getNumberV) + ], + (world, {condition, delta}) => changesExpectation(world, condition.val, delta) + ), + new View<{condition: EventV, value: Value}>(` + #### Remains + + * "Expect Remains " - Ensures that the given condition starts at and remains a given value + * E.g ."Expect Remains (CToken cZRX UnderlyingBalance Geoff) (Exactly 0)" + `, + "Remains", + [ + new Arg("condition", getEventV), + new Arg("value", getCoreValue) + ], + (world, {condition, value}) => remainsExpectation(world, condition.val, value) + ) + ]; +} + +export async function processExpectationEvent(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("Expectation", expectationCommands(), world, event, from); +} diff --git a/scenario/src/Event/InterestRateModelEvent.ts b/scenario/src/Event/InterestRateModelEvent.ts new file mode 100644 index 000000000..7276c06f5 --- /dev/null +++ b/scenario/src/Event/InterestRateModelEvent.ts @@ -0,0 +1,84 @@ +import {Event} from '../Event'; +import {addAction, World} from '../World'; +import {InterestRateModel} from '../Contract/InterestRateModel'; +import {buildInterestRateModel} from '../Builder/InterestRateModelBuilder'; +import {invoke} from '../Invokation'; +import { + getAddressV, + getEventV, + getNumberV, + getStringV, +} from '../CoreValue'; +import { + AddressV, + EventV, + NumberV, + StringV +} from '../Value'; +import {Arg, Command, processCommandEvent, View} from '../Command'; +import {getInterestRateModelData} from '../ContractLookup'; +import {verify} from '../Verify'; + +async function genInterestRateModel(world: World, from: string, params: Event): Promise { + let {world: nextWorld, interestRateModel, interestRateModelData} = await buildInterestRateModel(world, from, params); + world = nextWorld; + + world = addAction( + world, + `Deployed interest rate model (${interestRateModelData.description}) to address ${interestRateModel._address}`, + interestRateModelData.invokation + ); + + return world; +} + +async function verifyInterestRateModel(world: World, interestRateModel: InterestRateModel, apiKey: string, modelName: string, contractName: string): Promise { + if (world.isLocalNetwork()) { + world.printer.printLine(`Politely declining to verify on local network: ${world.network}.`); + } else { + await verify(world, apiKey, modelName, contractName, interestRateModel._address); + } + + return world; +} + +export function interestRateModelCommands() { + return [ + new Command<{params: EventV}>(` + #### Deploy + + * "Deploy ...params" - Generates a new interest rate model + * E.g. "InterestRateModel Deploy Fixed MyInterestRateModel 0.5" + * E.g. "InterestRateModel Deploy Whitepaper MyInterestRateModel 0.05 0.45" + * E.g. "InterestRateModel Deploy Standard MyInterestRateModel" + `, + "Deploy", + [ + new Arg("params", getEventV, {variadic: true}) + ], + (world, from, {params}) => genInterestRateModel(world, from, params.val) + ), + new View<{interestRateModelArg: StringV, apiKey: StringV}>(` + #### Verify + + * " Verify apiKey:" - Verifies InterestRateModel in Etherscan + * E.g. "InterestRateModel MyInterestRateModel Verify "myApiKey" + `, + "Verify", + [ + new Arg("interestRateModelArg", getStringV), + new Arg("apiKey", getStringV) + ], + async (world, {interestRateModelArg, apiKey}) => { + let [interestRateModel, name, data] = await getInterestRateModelData(world, interestRateModelArg.val); + + return await verifyInterestRateModel(world, interestRateModel, apiKey.val, name, data.get('contract')!) + }, + {namePos: 1} + ) + ]; +} + +export async function processInterestRateModelEvent(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("InterestRateModel", interestRateModelCommands(), world, event, from); +} diff --git a/scenario/src/Event/InvariantEvent.ts b/scenario/src/Event/InvariantEvent.ts new file mode 100644 index 000000000..9a94b9c8c --- /dev/null +++ b/scenario/src/Event/InvariantEvent.ts @@ -0,0 +1,83 @@ +import {Event} from '../Event'; +import {addInvariant, World} from '../World'; +import { + EventV, + Value +} from '../Value'; +import { + getCoreValue, + getEventV, +} from '../CoreValue'; +import {Invariant} from '../Invariant'; +import {StaticInvariant} from '../Invariant/StaticInvariant'; +import {RemainsInvariant} from '../Invariant/RemainsInvariant'; +import {SuccessInvariant} from '../Invariant/SuccessInvariant'; +import {formatEvent} from '../Formatter'; +import {Arg, View, processCommandEvent} from '../Command'; + + +async function staticInvariant(world: World, condition): Promise { + const currentValue = await getCoreValue(world, condition); + const invariant = new StaticInvariant(condition, currentValue); + + return addInvariant(world, invariant); +} + +async function remainsInvariant(world: World, condition: Event, value: Value): Promise { + const invariant = new RemainsInvariant(condition, value); + + // Immediately check value matches + await invariant.checker(world, true); + + return addInvariant(world, invariant); +} + +async function successInvariant(world: World): Promise { + const invariant = new SuccessInvariant(); + + return addInvariant(world, invariant); +} + +export function invariantCommands() { + return [ + new View<{condition: EventV}>(` + #### Static + + * "Static " - Ensures that the given condition retains a consistent value + * E.g ."Invariant Static (CToken cZRX UnderlyingBalance Geoff)" + `, + "Static", + [ + new Arg("condition", getEventV) + ], + (world, {condition}) => staticInvariant(world, condition.val) + ), + new View<{condition: EventV, value: Value}>(` + #### Remains + + * "Invariant Remains " - Ensures that the given condition starts at and remains a given value + * E.g ."Invariant Remains (CToken cZRX UnderlyingBalance Geoff) (Exactly 0)" + `, + "Remains", + [ + new Arg("condition", getEventV), + new Arg("value", getCoreValue) + ], + (world, {condition, value}) => remainsInvariant(world, condition.val, value) + ), + new View<{}>(` + #### Success + + * "Invariant Success" - Ensures that each transaction completes successfully + * E.g ."Invariant Success" + `, + "Success", + [], + (world, {}) => successInvariant(world) + ) + ]; +} + +export async function processInvariantEvent(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("Invariant", invariantCommands(), world, event, from); +} diff --git a/scenario/src/Event/MaximillionEvent.ts b/scenario/src/Event/MaximillionEvent.ts new file mode 100644 index 000000000..d8bd318d2 --- /dev/null +++ b/scenario/src/Event/MaximillionEvent.ts @@ -0,0 +1,104 @@ +import {Event} from '../Event'; +import {addAction, describeUser, World} from '../World'; +import {Maximillion} from '../Contract/Maximillion'; +import {invoke} from '../Invokation'; +import { + getAddressV, + getEventV, + getStringV +} from '../CoreValue'; +import { + AddressV, + EventV, + NumberV, + StringV +} from '../Value'; +import {Arg, Command, View, processCommandEvent} from '../Command'; +import {buildMaximillion} from '../Builder/MaximillionBuilder'; +import {getMaximillion} from '../ContractLookup'; +import {verify} from '../Verify'; + +function showTrxValue(world: World): string { + return new NumberV(world.trxInvokationOpts.get('value')).show(); +} + +async function genMaximillion(world: World, from: string, params: Event): Promise { + let {world: nextWorld, maximillion, maximillionData} = await buildMaximillion(world, from, params); + world = nextWorld; + + world = addAction( + world, + `Added Maximillion (${maximillionData.description}) at address ${maximillion._address}`, + maximillionData.invokation + ); + + return world; +} + +async function verifyMaximillion(world: World, maximillion: Maximillion, apiKey: string): Promise { + if (world.isLocalNetwork()) { + world.printer.printLine(`Politely declining to verify on local network: ${world.network}.`); + } else { + await verify(world, apiKey, "Maximillion", "Maximillion", maximillion._address); + } + + return world; +} + +async function repayBehalf(world: World, from: string, maximillion: Maximillion, behalf: string): Promise { + let showAmount = showTrxValue(world); + let invokation = await invoke(world, maximillion.methods.repayBehalf(behalf), from); + + world = addAction( + world, + `Maximillion: ${describeUser(world, from)} repays ${showAmount} of borrow on behalf of ${describeUser(world, behalf)}`, + invokation + ); + + return world; +} + +export function maximillionCommands() { + return [ + new Command<{maximillionParams: EventV}>(` + #### Deploy + + * "Maximillion Deploy ...maximillionParams" - Generates a new Maximillion + * E.g. "Maximillion Deploy" + `, + "Deploy", + [new Arg("maximillionParams", getEventV, {variadic: true})], + (world, from, {maximillionParams}) => genMaximillion(world, from, maximillionParams.val) + ), + new View<{maximillion: Maximillion, apiKey: StringV}>(` + #### Verify + + * "Maximillion Verify apiKey:" - Verifies Maximillion in Etherscan + * E.g. "Maximillion Verify "myApiKey" + `, + "Verify", + [ + new Arg("maximillion", getMaximillion, {implicit: true}), + new Arg("apiKey", getStringV) + ], + (world, {maximillion, apiKey}) => verifyMaximillion(world, maximillion, apiKey.val) + ), + new Command<{maximillion: Maximillion, behalf: AddressV}>(` + #### RepayBehalf + + * "RepayBehalf behalf:" - Repays up to given value of given user's borrow + * E.g. "(Trx Value 1.0e18 (Maximillion RepayBehalf Geoff))" + `, + "RepayBehalf", + [ + new Arg("maximillion", getMaximillion, {implicit: true}), + new Arg("behalf", getAddressV) + ], + (world, from, {maximillion, behalf}) => repayBehalf(world, from, maximillion, behalf.val) + ) + ]; +} + +export async function processMaximillionEvent(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("Maximillion", maximillionCommands(), world, event, from); +} diff --git a/scenario/src/Event/PriceOracleEvent.ts b/scenario/src/Event/PriceOracleEvent.ts new file mode 100644 index 000000000..252d83517 --- /dev/null +++ b/scenario/src/Event/PriceOracleEvent.ts @@ -0,0 +1,120 @@ +import {Event} from '../Event'; +import {addAction, World} from '../World'; +import {PriceOracle} from '../Contract/PriceOracle'; +import {buildPriceOracle, setPriceOracle} from '../Builder/PriceOracleBuilder'; +import {invoke} from '../Invokation'; +import { + getAddressV, + getEventV, + getExpNumberV, + getStringV +} from '../CoreValue'; +import { + AddressV, + EventV, + NumberV, + StringV +} from '../Value'; +import {Arg, Command, processCommandEvent, View} from '../Command'; +import {getPriceOracle} from '../ContractLookup'; +import {verify} from '../Verify'; +import {encodedNumber} from '../Encoding'; + +async function genPriceOracle(world: World, from: string, params: Event): Promise { + let {world: nextWorld, priceOracle, priceOracleData} = await buildPriceOracle(world, from, params); + world = nextWorld; + + world = addAction( + world, + `Deployed PriceOracle (${priceOracleData.description}) to address ${priceOracle._address}`, + priceOracleData.invokation! + ); + + return world; +} + +async function setPriceOracleFn(world: World, params: Event): Promise { + let {world: nextWorld, priceOracle, priceOracleData} = await setPriceOracle(world, params); + + return nextWorld; +} + +async function setPrice(world: World, from: string, priceOracle: PriceOracle, cToken: string, amount: NumberV): Promise { + return addAction( + world, + `Set price oracle price for ${cToken} to ${amount.show()}`, + await invoke(world, priceOracle.methods.setUnderlyingPrice(cToken, amount.encode()), from) + ); +} + +async function verifyPriceOracle(world: World, priceOracle: PriceOracle, apiKey: string, contractName: string): Promise { + if (world.isLocalNetwork()) { + world.printer.printLine(`Politely declining to verify on local network: ${world.network}.`); + } else { + await verify(world, apiKey, "PriceOracle", contractName, priceOracle._address); + } + + return world; +} + +export function priceOracleCommands() { + return [ + new Command<{params: EventV}>(` + #### Deploy + + * "Deploy ...params" - Generates a new price oracle + * E.g. "PriceOracle Deploy Fixed 1.0" + * E.g. "PriceOracle Deploy Simple" + * E.g. "PriceOracle Deploy NotPriceOracle" + `, + "Deploy", + [ + new Arg("params", getEventV, {variadic: true}) + ], + (world, from, {params}) => genPriceOracle(world, from, params.val) + ), + new Command<{params: EventV}>(` + #### Set + + * "Set ...params" - Sets the price oracle to given deployed contract + * E.g. "PriceOracle Set Standard \"0x...\" \"My Already Deployed Oracle\"" + `, + "Set", + [ + new Arg("params", getEventV, {variadic: true}) + ], + (world, from, {params}) => setPriceOracleFn(world, params.val) + ),new Command<{priceOracle: PriceOracle, cToken: AddressV, amount: NumberV}>(` + #### SetPrice + + * "SetPrice " - Sets the per-ether price for the given cToken + * E.g. "PriceOracle SetPrice cZRX 1.0" + `, + "SetPrice", + [ + new Arg("priceOracle", getPriceOracle, {implicit: true}), + new Arg("cToken", getAddressV), + new Arg("amount", getExpNumberV) + ], + (world, from, {priceOracle, cToken, amount}) => setPrice(world, from, priceOracle, cToken.val, amount) + ), + new View<{priceOracle: PriceOracle, apiKey: StringV, contractName: StringV}>(` + #### Verify + + * "Verify apiKey: contractName:=PriceOracle" - Verifies PriceOracle in Etherscan + * E.g. "PriceOracle Verify "myApiKey" + `, + "Verify", + [ + new Arg("priceOracle", getPriceOracle, {implicit: true}), + new Arg("apiKey", getStringV), + new Arg("contractName", getStringV, {default: new StringV("PriceOracle")}) + ], + (world, {priceOracle, apiKey, contractName}) => verifyPriceOracle(world, priceOracle, apiKey.val, contractName.val) + ) + ]; +} + +export async function processPriceOracleEvent(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("PriceOracle", priceOracleCommands(), world, event, from); +} diff --git a/scenario/src/Event/PriceOracleProxyEvent.ts b/scenario/src/Event/PriceOracleProxyEvent.ts new file mode 100644 index 000000000..57a8e3e9d --- /dev/null +++ b/scenario/src/Event/PriceOracleProxyEvent.ts @@ -0,0 +1,81 @@ +import {Event} from '../Event'; +import {addAction, World} from '../World'; +import {PriceOracleProxy} from '../Contract/PriceOracleProxy'; +import {buildPriceOracleProxy} from '../Builder/PriceOracleProxyBuilder'; +import {invoke} from '../Invokation'; +import { + getAddressV, + getEventV, + getExpNumberV, + getStringV +} from '../CoreValue'; +import { + AddressV, + EventV, + NumberV, + StringV +} from '../Value'; +import {Arg, Command, processCommandEvent, View} from '../Command'; +import {getPriceOracleProxy} from '../ContractLookup'; +import {verify} from '../Verify'; +import {encodedNumber} from '../Encoding'; + +async function genPriceOracleProxy(world: World, from: string, params: Event): Promise { + let priceOracleProxy; + let invokation; + + ({world, priceOracleProxy, invokation} = await buildPriceOracleProxy(world, from, params)); + + world = addAction( + world, + `Deployed PriceOracleProxy to address ${priceOracleProxy._address}`, + invokation + ); + + return world; +} + +async function verifyPriceOracleProxy(world: World, priceOracleProxy: PriceOracleProxy, apiKey: string, contractName: string): Promise { + if (world.isLocalNetwork()) { + world.printer.printLine(`Politely declining to verify on local network: ${world.network}.`); + } else { + await verify(world, apiKey, "PriceOracleProxy", contractName, priceOracleProxy._address); + } + + return world; +} + +export function priceOracleProxyCommands() { + return [ + new Command<{params: EventV}>(` + #### Deploy + + * "Deploy ...params" - Generates a new price oracle proxy + * E.g. "PriceOracleProxy Deploy (Unitroller Address) (PriceOracle Address) (cEther Address)" + `, + "Deploy", + [ + new Arg("params", getEventV, {variadic: true}) + ], + (world, from, {params}) => genPriceOracleProxy(world, from, params.val) + ), + new View<{priceOracleProxy: PriceOracleProxy, apiKey: StringV, contractName: StringV}>(` + #### Verify + + * "Verify apiKey: contractName:=PriceOracleProxy" - Verifies PriceOracleProxy in Etherscan + * E.g. "PriceOracleProxy Verify "myApiKey" + `, + "Verify", + [ + new Arg("priceOracleProxy", getPriceOracleProxy, {implicit: true}), + new Arg("apiKey", getStringV), + new Arg("contractName", getStringV, {default: new StringV("PriceOracleProxy")}) + ], + (world, {priceOracleProxy, apiKey, contractName}) => verifyPriceOracleProxy(world, priceOracleProxy, apiKey.val, contractName.val) + ) + ]; +} + +export async function processPriceOracleProxyEvent(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("PriceOracleProxy", priceOracleProxyCommands(), world, event, from); +} diff --git a/scenario/src/Event/TrxEvent.ts b/scenario/src/Event/TrxEvent.ts new file mode 100644 index 000000000..b559129b9 --- /dev/null +++ b/scenario/src/Event/TrxEvent.ts @@ -0,0 +1,56 @@ +import {World} from '../World'; +import {Event} from '../Event'; +import {processCoreEvent} from '../CoreEvent'; +import { + EventV, + NumberV +} from '../Value'; +import { + getEventV, + getNumberV +} from '../CoreValue'; +import {Arg, Command, processCommandEvent} from '../Command'; +import {encodedNumber} from '../Encoding'; + +async function setTrxValue(world: World, value: encodedNumber): Promise { + return world.update('trxInvokationOpts', (t) => t.set('value', value)); +} + +async function setTrxGasPrice(world: World, gasPrice: encodedNumber): Promise { + return world.update('trxInvokationOpts', (t) => t.set('gasPrice', gasPrice.toString())); +} + +export function trxCommands() { + return [ + new Command<{amount: NumberV, event: EventV}>(` + #### Value + + * "Value " - Runs event with a set amount for any transactions + * E.g. "Value 1.0e18 (CToken cEth Mint 1.0e18)" + `, + "Value", + [ + new Arg("amount", getNumberV), + new Arg("event", getEventV) + ], + async (world, from, {amount, event}) => processCoreEvent(await setTrxValue(world, amount.encode()), event.val, from) + ), + new Command<{gasPrice: NumberV, event: EventV}>(` + #### GasPrice + + * "GasPrice " - Runs event with a given gas price + * E.g. "GasPrice 0 (CToken cEth Mint 1.0e18)" + `, + "GasPrice", + [ + new Arg("gasPrice", getNumberV), + new Arg("event", getEventV) + ], + async (world, from, {gasPrice, event}) => processCoreEvent(await setTrxGasPrice(world, gasPrice.encode()), event.val, from) + ) + ]; +} + +export async function processTrxEvent(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("Trx", trxCommands(), world, event, from); +} diff --git a/scenario/src/Event/UnitrollerEvent.ts b/scenario/src/Event/UnitrollerEvent.ts new file mode 100644 index 000000000..ed963832f --- /dev/null +++ b/scenario/src/Event/UnitrollerEvent.ts @@ -0,0 +1,98 @@ +import {Event} from '../Event'; +import {addAction, describeUser, World} from '../World'; +import {Unitroller} from '../Contract/Unitroller'; +import {ComptrollerImpl} from '../Contract/ComptrollerImpl'; +import {invoke} from '../Invokation'; +import { + getEventV, + getStringV +} from '../CoreValue'; +import { + EventV, + StringV +} from '../Value'; +import {Arg, Command, View, processCommandEvent} from '../Command'; +import {ComptrollerErrorReporter} from '../ErrorReporter'; +import {buildUnitroller} from '../Builder/UnitrollerBuilder'; +import {getComptrollerImpl, getUnitroller} from '../ContractLookup'; +import {verify} from '../Verify'; + +async function genUnitroller(world: World, from: string, params: Event): Promise { + let {world: nextWorld, unitroller, unitrollerData} = await buildUnitroller(world, from, params); + world = nextWorld; + + world = addAction( + world, + `Added Unitroller (${unitrollerData.description}) at address ${unitroller._address}`, + unitrollerData.invokation + ); + + return world; +} + +async function verifyUnitroller(world: World, unitroller: Unitroller, apiKey: string): Promise { + if (world.isLocalNetwork()) { + world.printer.printLine(`Politely declining to verify on local network: ${world.network}.`); + } else { + await verify(world, apiKey, "Unitroller", "Unitroller", unitroller._address); + } + + return world; +} + +async function setPendingImpl(world: World, from: string, unitroller: Unitroller, comptrollerImpl: ComptrollerImpl): Promise { + let invokation = await invoke(world, unitroller.methods._setPendingImplementation(comptrollerImpl._address), from, ComptrollerErrorReporter); + + world = addAction( + world, + `Set pending comptroller impl to ${comptrollerImpl.name}`, + invokation + ); + + return world; +} + +export function unitrollerCommands() { + return [ + new Command<{unitrollerParams: EventV}>(` + #### Deploy + + * "Unitroller Deploy ...unitrollerParams" - Generates a new Unitroller + * E.g. "Unitroller Deploy" + `, + "Deploy", + [new Arg("unitrollerParams", getEventV, {variadic: true})], + (world, from, {unitrollerParams}) => genUnitroller(world, from, unitrollerParams.val) + ), + new View<{unitroller: Unitroller, apiKey: StringV}>(` + #### Verify + + * "Unitroller Verify apiKey:" - Verifies Unitroller in Etherscan + * E.g. "Unitroller Verify "myApiKey" + `, + "Verify", + [ + new Arg("unitroller", getUnitroller, {implicit: true}), + new Arg("apiKey", getStringV) + ], + (world, {unitroller, apiKey}) => verifyUnitroller(world, unitroller, apiKey.val) + ), + new Command<{unitroller: Unitroller, comptrollerImpl: ComptrollerImpl}>(` + #### SetPendingImpl + + * "SetPendingImpl impl:" - Sets the pending comptroller implementation for this unitroller + * E.g. "Unitroller SetPendingImpl MyScenImpl" - Sets the current comptroller implementation to MyScenImpl + `, + "SetPendingImpl", + [ + new Arg("unitroller", getUnitroller, {implicit: true}), + new Arg("comptrollerImpl", getComptrollerImpl) + ], + (world, from, {unitroller, comptrollerImpl}) => setPendingImpl(world, from, unitroller, comptrollerImpl) + ) + ]; +} + +export async function processUnitrollerEvent(world: World, event: Event, from: string | null): Promise { + return await processCommandEvent("Unitroller", unitrollerCommands(), world, event, from); +} diff --git a/scenario/src/Expectation.ts b/scenario/src/Expectation.ts new file mode 100644 index 000000000..7823f87fd --- /dev/null +++ b/scenario/src/Expectation.ts @@ -0,0 +1,4 @@ + +export interface Expectation { + checker: (world: any) => Promise; +} diff --git a/scenario/src/Expectation/ChangesExpectation.ts b/scenario/src/Expectation/ChangesExpectation.ts new file mode 100644 index 000000000..3cc182c47 --- /dev/null +++ b/scenario/src/Expectation/ChangesExpectation.ts @@ -0,0 +1,47 @@ +import {Expectation} from '../Expectation'; +import {fail, World} from '../World'; +import {getCoreValue} from '../CoreValue'; +import {Value, NumberV} from '../Value'; +import {Event} from '../Event'; +import {formatEvent} from '../Formatter'; +import {BigNumber} from 'bignumber.js'; + +function asNumberV(v: Value): NumberV { + if (v instanceof NumberV) { + return v; + } else { + throw new Error(`Expected NumberV for ChangesExpectation, got ${v.toString()}`); + } +} + +export class ChangesExpectation implements Expectation { + condition: Event; + originalValue: NumberV; + delta: NumberV; + expected: NumberV; + + constructor(condition: Event, originalValue: Value, delta: Value) { + this.condition = condition; + this.originalValue = asNumberV(originalValue); + this.delta = asNumberV(delta); + this.expected = this.originalValue.add(this.delta); + } + + async getCurrentValue(world: World): Promise { + return await getCoreValue(world, this.condition); + }; + + async checker(world: World, initialCheck: boolean=false): Promise { + const currentValue = asNumberV(await this.getCurrentValue(world)); + + if (!currentValue.compareTo(world, this.expected)) { + const trueDelta = currentValue.sub(this.originalValue); + + fail(world, `${this.toString()} instead had value \`${currentValue.toString()}\` (true delta: ${trueDelta.toString()})`); + } + } + + toString() { + return `ChangesExpectation: condition=${formatEvent(this.condition)}, originalValue=${this.originalValue.toString()}, delta=${this.delta.toString()}, expected=${this.expected.toString()}`; + } +} diff --git a/scenario/src/Expectation/RemainsExpectation.ts b/scenario/src/Expectation/RemainsExpectation.ts new file mode 100644 index 000000000..9506cc473 --- /dev/null +++ b/scenario/src/Expectation/RemainsExpectation.ts @@ -0,0 +1,32 @@ +import {Expectation} from '../Expectation'; +import {fail, World} from '../World'; +import {getCoreValue} from '../CoreValue'; +import {Value} from '../Value'; +import {Event} from '../Event'; +import {formatEvent} from '../Formatter'; + +export class RemainsExpectation implements Expectation { + condition: Event; + value: Value; + + constructor(condition: Event, value: Value) { + this.condition = condition; + this.value = value; + } + + async getCurrentValue(world: World): Promise { + return await getCoreValue(world, this.condition); + }; + + async checker(world: World, initialCheck: boolean=false): Promise { + const currentValue = await this.getCurrentValue(world); + + if (!this.value.compareTo(world, currentValue)) { + fail(world, `${this.toString()} failed as value ${initialCheck ? 'started as' : 'became'} \`${currentValue.toString()}\``); + } + } + + toString() { + return `RemainsExpectation: condition=${formatEvent(this.condition)}, value=${this.value.toString()}`; + } +} diff --git a/scenario/src/File.ts b/scenario/src/File.ts new file mode 100644 index 000000000..84df15318 --- /dev/null +++ b/scenario/src/File.ts @@ -0,0 +1,32 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +export function getNetworkPath(basePath: string | null, network: string, name: string, extension: string | null='json'): string { + if (!basePath) { + throw new Error(`Cannot read file when missing base path`); + } + + return path.join(basePath, 'networks', `${network}${name}${extension ? `.${extension}` : ''}`); +} + +export async function readFile(file: string, def: T, fn: (data: string) => T): Promise { + return new Promise((resolve, reject) => { + fs.access(file, fs.constants.F_OK, (err) => { + if (err) { + resolve(def); + } else { + fs.readFile(file, 'utf8', (err, data) => { + return err ? reject(err) : resolve(fn(data)); + }); + } + }); + }); +} + +export async function writeFile(file: string, data: string): Promise { + return new Promise((resolve, reject) => { + fs.writeFile(file, data, (err) => { + return err ? reject(err) : resolve(); + }); + }); +} diff --git a/scenario/src/Formatter.ts b/scenario/src/Formatter.ts new file mode 100644 index 000000000..55e2d4806 --- /dev/null +++ b/scenario/src/Formatter.ts @@ -0,0 +1,25 @@ +import {Event} from './Event'; + +// Effectively the opposite of parse +export function formatEvent(event: Event, outter=true): string { + if (Array.isArray(event)) { + if (event.length === 2 && typeof event[0] === "string" && (event[0]).toLowerCase() === "exactly") { + return event[1].toString(); + } + + let mapped = event.map(e => formatEvent(e, false)); + let joined = mapped.join(' '); + + if (outter) { + return joined; + } else { + return `(${joined})`; + } + } else { + return event; + } +} + +export function formatError(err: any) { + return JSON.stringify(err); // yeah... for now +} diff --git a/scenario/src/Help.ts b/scenario/src/Help.ts new file mode 100644 index 000000000..c67d53170 --- /dev/null +++ b/scenario/src/Help.ts @@ -0,0 +1,64 @@ +import {Event} from './Event'; +import {Expression} from './Command'; +import {mustString} from './Utils'; +import {Printer} from './Printer'; + +export function printHelp(printer: Printer, event: Event, expressions: Expression[], path: string[]=[]) { + if (event.length === 0) { + let banner; + + if (path.length === 0) { + banner = ( +` +## Compound Command Runner + +The Compound Command Runner makes it easy to interact with Compound. You can input simple commands +and it will construct Web3 calls to pull data or generate transactions. A list of available commands +is included below. To dig further into a command run \`Help \`, such as \`Help From\` or for +sub-commands run \`Help CToken\` or \`Help CToken Mint\`. +`).trim(); + } else { + if (expressions.length > 0) { + banner = `### ${path.join(" ")} Sub-Commands`; + } + } + + if (!!banner) { + printer.printMarkdown(banner); + } + + expressions.forEach((expression) => { + printer.printMarkdown(`\n${expression.doc}`); + if (expression.subExpressions.length > 0) { + printer.printMarkdown(`For more information, run: \`Help ${path} ${expression.name}\``); + } + }); + } else { + const [first, ...rest] = event; + const expressionName = mustString(first); + + let expression = expressions.find((expression) => expression.name.toLowerCase() === expressionName.toLowerCase()); + + if (expression) { + if (rest.length === 0) { + printer.printMarkdown(`${expression.doc}`); + } + + printHelp(printer, rest, expression.subExpressions, path.concat(expression.name)); + } else { + let matchingExpressions = expressions.filter((expression) => expression.name.toLowerCase().startsWith(expressionName.toLowerCase())); + + if (matchingExpressions.length === 0) { + printer.printLine(`\nError: cannot find help docs for ${path.concat(first).join(" ")}`); + } else { + if (rest.length === 0) { + matchingExpressions.forEach((expression) => { + printer.printMarkdown(`${expression.doc}`); + }); + } else { + printer.printLine(`\nError: cannot find help docs for ${path.concat(event).join(" ")}`); + } + } + } + } +} diff --git a/scenario/src/HistoricReadline.ts b/scenario/src/HistoricReadline.ts new file mode 100644 index 000000000..ef9bd3dd7 --- /dev/null +++ b/scenario/src/HistoricReadline.ts @@ -0,0 +1,35 @@ +import * as readline from 'readline'; +import * as fs from 'fs'; +import {readFile} from './File'; + +let readlineAny = readline; + +export async function createInterface(options): Promise { + let history: string[] = await readFile(options['path'], [], (x) => x.split("\n")); + let cleanHistory = history.filter((x) => !!x).reverse(); + + readlineAny.kHistorySize = Math.max(readlineAny.kHistorySize, options['maxLength']); + + let rl = readline.createInterface(options); + let rlAny = rl; + + let oldAddHistory = rlAny._addHistory; + + rlAny._addHistory = function() { + let last = rlAny.history[0]; + let line = oldAddHistory.call(rl); + + // TODO: Should this be sync? + if (line.length > 0 && line != last) { + fs.appendFileSync(options['path'], `${line}\n`); + } + + // TODO: Truncate file? + + return line; + } + + rlAny.history.push.apply(rlAny.history, cleanHistory); + + return rl; +} diff --git a/scenario/src/Invariant.ts b/scenario/src/Invariant.ts new file mode 100644 index 000000000..fc5211c0a --- /dev/null +++ b/scenario/src/Invariant.ts @@ -0,0 +1,5 @@ + +export interface Invariant { + held: boolean + checker: (world: any) => Promise; +} diff --git a/scenario/src/Invariant/RemainsInvariant.ts b/scenario/src/Invariant/RemainsInvariant.ts new file mode 100644 index 000000000..b98a4c635 --- /dev/null +++ b/scenario/src/Invariant/RemainsInvariant.ts @@ -0,0 +1,33 @@ +import {Invariant} from '../Invariant'; +import {fail, World} from '../World'; +import {getCoreValue} from '../CoreValue'; +import {Value} from '../Value'; +import {Event} from '../Event'; +import {formatEvent} from '../Formatter'; + +export class RemainsInvariant implements Invariant { + condition: Event; + value: Value; + held = false; + + constructor(condition: Event, value: Value) { + this.condition = condition; + this.value = value; + } + + async getCurrentValue(world: World): Promise { + return await getCoreValue(world, this.condition); + }; + + async checker(world: World, initialCheck: boolean=false): Promise { + const currentValue = await this.getCurrentValue(world); + + if (!this.value.compareTo(world, currentValue)) { + fail(world, `Static invariant broken! Expected ${this.toString()} to remain static value \`${this.value}\` but ${initialCheck ? 'started as' : 'became'} \`${currentValue}\``); + } + } + + toString() { + return `RemainsInvariant: condition=${formatEvent(this.condition)}, value=${this.value.toString()}`; + } +} diff --git a/scenario/src/Invariant/StaticInvariant.ts b/scenario/src/Invariant/StaticInvariant.ts new file mode 100644 index 000000000..7a464c310 --- /dev/null +++ b/scenario/src/Invariant/StaticInvariant.ts @@ -0,0 +1,33 @@ +import {Invariant} from '../Invariant'; +import {fail, World} from '../World'; +import {getCoreValue} from '../CoreValue'; +import {Value} from '../Value'; +import {Event} from '../Event'; +import {formatEvent} from '../Formatter'; + +export class StaticInvariant implements Invariant { + condition: Event; + value: Value; + held = false; + + constructor(condition: Event, value: Value) { + this.condition = condition; + this.value = value; + } + + async getCurrentValue(world: World): Promise { + return await getCoreValue(world, this.condition); + }; + + async checker(world: World): Promise { + const currentValue = await this.getCurrentValue(world); + + if (!this.value.compareTo(world, currentValue)) { + fail(world, `Static invariant broken! Expected ${this.toString()} to remain static value \`${this.value}\` but became \`${currentValue}\``); + } + } + + toString() { + return `StaticInvariant: condition=${formatEvent(this.condition)}, value=${this.value.toString()}`; + } +} diff --git a/scenario/src/Invariant/SuccessInvariant.ts b/scenario/src/Invariant/SuccessInvariant.ts new file mode 100644 index 000000000..9abd2b49e --- /dev/null +++ b/scenario/src/Invariant/SuccessInvariant.ts @@ -0,0 +1,21 @@ +import {Invariant} from '../Invariant'; +import {fail, World} from '../World'; +import {getCoreValue} from '../CoreValue'; +import {Value} from '../Value'; +import {Event} from '../Event'; + +export class SuccessInvariant implements Invariant { + held = false; + + constructor() {} + + async checker(world: World): Promise { + if (world.lastInvokation && !world.lastInvokation.success()) { + fail(world, `Success invariant broken! Expected successful execution, but had error ${world.lastInvokation.toString()}`); + } + } + + toString() { + return `SuccessInvariant`; + } +} diff --git a/scenario/src/Invokation.ts b/scenario/src/Invokation.ts new file mode 100644 index 000000000..450e796e2 --- /dev/null +++ b/scenario/src/Invokation.ts @@ -0,0 +1,274 @@ +import {ErrorReporter, NoErrorReporter, ComptrollerErrorReporter} from './ErrorReporter'; +import {mustArray} from './Utils'; +import {World} from './World'; +import {encodedNumber} from './Encoding'; + +const errorRegex = /^(.*) \((\d+)\)$/ + +function getErrorCode(revertMessage: string): [string, number] | null { + let res = errorRegex.exec(revertMessage); + + if (res) { + return [res[1], Number(res[2])]; + } else { + return null; + } +} + +export interface InvokationOpts { + from?: string, + gas?: number, + gasPrice?: number +} + +export class InvokationError extends Error { + err : Error + // function : string + // arguments : {[]} + + constructor(err: Error) { + super(err.message); + this.err = err; + } + + toString() { + return `InvokationError`; + } +} + +export class InvokationRevertFailure extends InvokationError { + errCode: number + error : string | null + errMessage : string + + constructor(err: Error, errMessage: string, errCode: number, error: string | null) { + super(err); + + this.errMessage = errMessage; + this.errCode = errCode; + this.error = error; + } + + toString() { + return `InvokationRevertError`; + } +} + +interface Argument { + name: string + type: string +} + +interface Method { + name: string + inputs: Argument[] +} + +export interface Callable { + estimateGas: (InvokationOpts?) => Promise + call: (InvokationOpts?) => Promise + _method: Method + arguments: any[] +} + +export interface Sendable extends Callable { + send: (InvokationOpts) => Promise +} + +export interface Receipt { + // TODO: Add more transaction details + blockNumber: number + transactionHash: string + gasUsed: number + + events: {[event: string]: {returnValues: {[key: string]: any}}} +} + +export class Failure { + error: string + info: string + detail: string + + constructor(error: string, info: string, detail: string) { + this.error = error; + this.info = info; + this.detail = detail; + } + + toString(): string { + return `Failure`; + } + + equals(other: Failure): boolean { + return ( + this.error === other.error && + this.info === other.info && + this.detail === other.detail + ); + } +} + +export class Invokation { + value: T | null + receipt: Receipt | null + error: Error | null + failures: Failure[] + method: string | null + args: {arg: string, val: any}[] + errorReporter: ErrorReporter + + constructor(value: T | null, receipt: Receipt | null, error: Error | null, fn: Callable | null, errorReporter: ErrorReporter=NoErrorReporter) { + this.value = value; + this.receipt = receipt; + this.error = error; + this.errorReporter = errorReporter; + + if (fn !== null) { + this.method = fn._method.name; + this.args = fn.arguments.map((argument, i) => ({arg: fn._method.inputs[i].name, val: argument})); + } else { + this.method = null; + this.args = []; + } + + if (receipt !== null && receipt.events["Failure"]) { + const failures = mustArray(receipt.events["Failure"]); + + this.failures = failures.map((failure) => { + const {'error': errorVal, 'info': infoVal, 'detail': detailVal} = failure.returnValues; + + return new Failure( + errorReporter.getError(errorVal) || `unknown error=${errorVal}`, + errorReporter.getInfo(infoVal) || `unknown info=${infoVal}`, + errorReporter.getDetail(errorVal, detailVal) + ); + }); + } else { + this.failures = []; + } + } + + success(): boolean { + return ( + this.error === null && this.failures.length === 0 + ); + } + + invokation(): string { + if (this.method) { + let argStr = this.args.map(({arg, val}) => `${arg}=${val.toString()}`).join(','); + return `"${this.method}(${argStr})"`; + } else { + return `unknown method`; + } + } + + toString(): string { + return `Invokation<${this.invokation()}, tx=${this.receipt ? this.receipt.transactionHash : ''}, value=${this.value ? this.value.toString() : ''}, error=${this.error}, failures=${this.failures.toString()}>`; + } +} + +export async function fallback(world: World, from: string, to: string, value: encodedNumber): Promise> { + let trxObj = { + from: from, + to: to, + value: value + }; + + let estimateGas = async (opts: InvokationOpts) => { + let trxObjMerged = { + ...trxObj, + ...opts + }; + + return await world.web3.eth.estimateGas(trxObjMerged); + }; + + let call = async (opts: InvokationOpts) => { + let trxObjMerged = { + ...trxObj, + ...opts + }; + + return await world.web3.eth.call(trxObjMerged); + }; + + let send = async (opts: InvokationOpts) => { + let trxObjMerged = { + ...trxObj, + ...opts + }; + + let receipt = await world.web3.eth.sendTransaction(trxObjMerged); + receipt.events = {}; + + return receipt; + } + + let fn: Sendable = { + estimateGas: estimateGas, + call: call, + send: send, + _method: { + name: "fallback", + inputs: [] + }, + arguments: [] + } + + return invoke(world, fn, from, NoErrorReporter); +} + +export async function invoke(world: World, fn: Sendable, from: string, errorReporter: ErrorReporter=NoErrorReporter): Promise> { + let value: T | null = null; + let result: Receipt | null = null; + let worldInvokationOpts = world.getInvokationOpts({from: from}); + let trxInvokationOpts = world.trxInvokationOpts.toJS(); + + let invokationOpts = { + ...worldInvokationOpts, + ...trxInvokationOpts + }; + + try{ + const gas = await fn.estimateGas({...invokationOpts}); + invokationOpts = { + ...invokationOpts, + gas: gas * 2 + }; + + let error: null | Error = null; + + try { + value = await fn.call({...invokationOpts}); + } catch (err) { + error = new InvokationError(err); + } + + if (world.dryRun) { + world.printer.printLine(`Dry run: invoking \`${fn._method.name}\``); + result = { + blockNumber: -1, + transactionHash: "0x", + gasUsed: 0, + events: {} + }; + } else { + result = await fn.send({...invokationOpts}); + } + + return new Invokation(value, result, null, fn, errorReporter); + } catch (err) { + if (errorReporter) { + let decoded = getErrorCode(err.message); + + if (decoded) { + let [errMessage, errCode] = decoded; + + return new Invokation(value, result, new InvokationRevertFailure(err, errMessage, errCode, errorReporter.getError(errCode)), fn, errorReporter); + } + } + + return new Invokation(value, result, new InvokationError(err), fn, errorReporter); + } +} diff --git a/scenario/src/Macro.ts b/scenario/src/Macro.ts new file mode 100644 index 000000000..a0a686733 --- /dev/null +++ b/scenario/src/Macro.ts @@ -0,0 +1,98 @@ +import {Event} from './Event'; + +interface Arg { + arg: any + def: any + splat: any +} + +interface Macro { + args: Arg[] + steps: Event +} + +type ArgMap = {[arg: string]: Event}; +type NamedArg = { argName: string, argValue: Event }; +type ArgValue = Event | NamedArg; + +export type Macros = {[eventName: string]: Macro}; + +export function expandEvent(macros: Macros, event: Event): Event[] { + const [eventName, ...eventArgs] = event; + + if (macros[eventName]) { + let expanded = expandMacro(macros[eventName], eventArgs); + + // Recursively expand steps + return expanded.map(event => expandEvent(macros, event)).flat(); + } else { + return [event]; + } +} + +function getArgValues(eventArgs: ArgValue[], macroArgs: Arg[]): ArgMap { + const eventArgNameMap: ArgMap = {}; + const eventArgIndexed: Event[] = []; + const argValues: ArgMap = {}; + let usedNamedArg: boolean = false; + let usedSplat: boolean = false; + + eventArgs.forEach((eventArg) => { + if (eventArg.hasOwnProperty('argName')) { + const {argName, argValue} = eventArg; + + eventArgNameMap[argName] = argValue; + usedNamedArg = true; + } else { + if (usedNamedArg) { + throw new Error("Cannot use positional arg after named arg in macro invokation."); + } + + eventArgIndexed.push(eventArg); + } + }); + + macroArgs.forEach(({arg, def, splat}, argIndex) => { + let val; + + if (usedSplat) { + throw new Error("Cannot have arg after splat arg"); + } + + if (eventArgNameMap[arg] !== undefined) { + val = eventArgNameMap[arg]; + } else if (splat) { + val = eventArgIndexed.slice(argIndex); + usedSplat = true; + } else if (eventArgIndexed[argIndex] !== undefined) { + val = eventArgIndexed[argIndex]; + } else if (def !== undefined) { + val = def; + } else { + throw new Error("Macro cannot find arg value for " + arg); + } + argValues[arg] = val; + }); + + return argValues; +} + +export function expandMacro(macro: Macro, event: Event): Event[] { + const argValues = getArgValues(event, macro.args); + + function expandStep(step) { + return step.map((token) => { + if (argValues[token] !== undefined) { + return argValues[token]; + } else { + if (Array.isArray(token)) { + return expandStep(token); + } else { + return token; + } + } + }); + }; + + return macro.steps.map(expandStep); +} diff --git a/scenario/src/Networks.ts b/scenario/src/Networks.ts new file mode 100644 index 000000000..b5456fca6 --- /dev/null +++ b/scenario/src/Networks.ts @@ -0,0 +1,140 @@ +import {fromJS, Map} from 'immutable'; +import {World} from './World'; +import {Invokation} from './Invokation'; +import {ABI, Contract, setContractName} from './Contract'; +import {getNetworkPath, readFile, writeFile} from './File'; + +type Networks = Map; + +interface ExtraData { + index: string[] + data: object | string | number +} + +export function parseNetworkFile(data: string | object): Networks { + return fromJS(typeof data === "string" ? JSON.parse(data) : data); +} + +function serializeNetworkFile(networks: Networks): string { + return JSON.stringify(networks.toJSON(), null, 4); +} + +function readNetworkFile(world: World, isABI: boolean): Promise { + return readFile(getNetworkPath(world.basePath, world.network, isABI ? '-abi' : ''), Map({}), parseNetworkFile); +} + +function writeNetworkFile(world: World, networks: Networks, isABI: boolean): Promise { + return writeFile(getNetworkPath(world.basePath, world.network, isABI ? '-abi' : ''), serializeNetworkFile(networks)); +} + +export function storeContract(world: World, contract: Contract, name: string, extraData: ExtraData[]): World { + contract = setContractName(name, contract); + + world = world.set('lastContract', contract); + world = world.setIn(['contractIndex', contract._address.toLowerCase()], contract); + + world = world.update('contractData', (contractData) => { + return extraData.reduce((acc, {index, data}) => { + if (typeof data !== 'string' && typeof data !== 'number') { + // Store extra data as an immutable + data = Map(data); + } + + return acc.setIn(index, data); + }, contractData); + }); + + return world; +} + +export async function saveContract(world: World, contract: Contract, name: string, extraData: ExtraData[]): Promise { + let networks = await readNetworkFile(world, false); + let networksABI = await readNetworkFile(world, true); + + networks = extraData.reduce((acc, {index, data}) => acc.setIn(index, data), networks); + networksABI = networksABI.set(name, contract._jsonInterface); + + // Don't write during a dry-run + if (!world.dryRun) { + await writeNetworkFile(world, networks, false); + await writeNetworkFile(world, networksABI, true); + } +} + +// Merges a contract into another, which is important for delegation +export async function mergeContractABI(world: World, targetName: string, contractTarget: Contract, a: string, b: string): Promise { + let networks = await readNetworkFile(world, false); + let networksABI = await readNetworkFile(world, true); + let aABI = networksABI.get(a); + let bABI = networksABI.get(b); + + if (!aABI) { + throw new Error(`Missing contract ABI for ${a}`); + } + + if (!bABI) { + throw new Error(`Missing contract ABI for ${b}`); + } + + const fullABI = aABI.toJS().concat(bABI.toJS()); + + // Store Comptroller address + networks = networks.setIn(['Contracts', targetName], contractTarget._address); + world = world.setIn(['contractData', 'Contracts', targetName], contractTarget._address); + + networksABI = networksABI.set(targetName, fullABI); + + let mergedContract = new world.web3.eth.Contract(fullABI, contractTarget._address, {}); + + world = world.setIn(['contractIndex', contractTarget._address.toLowerCase()], setContractName(targetName, mergedContract)); + + // Don't write during a dry-run + if (!world.dryRun) { + await writeNetworkFile(world, networks, false); + await writeNetworkFile(world, networksABI, true); + } + + return world; +} + +export async function loadContracts(world: World): Promise<[World, string[]]> { + let networks = await readNetworkFile(world, false); + let networksABI = await readNetworkFile(world, true); + + return loadContractData(world, networks, networksABI); +} + +export async function loadContractData(world: World, networks: Networks, networksABI: Networks): Promise<[World, string[]]> { + // Pull off contracts value and the rest is "extra" + let contractInfo: string[] = []; + let contracts = networks.get('Contracts') || Map({}); + + world = contracts.reduce((world: World, address: string, name: string) => { + let abi: ABI[] = networksABI.has(name) ? networksABI.get(name).toJS() : []; + let contract = new world.web3.eth.Contract(abi, address, {}); + + contractInfo.push(`${name}: ${address}`); + + // Store the contract + return world.setIn(['contractIndex', contract._address.toLowerCase()], setContractName(name, contract)); + }, world); + + world = world.update('contractData', (contractData) => contractData.mergeDeep(networks)); + + return [world, contractInfo]; +} + +export async function storeAndSaveContract(world: World, contract: Contract, name: string, invokation: Invokation | null, extraData: ExtraData[]): Promise { + extraData.push({index: ['Contracts', name], data: contract._address}); + if (contract.constructorAbi) { + extraData.push({index: ['Constructors', name], data: contract.constructorAbi}); + } + if (invokation && invokation.receipt) { + extraData.push({index: ['Blocks', name], data: invokation.receipt.blockNumber}); + } + + world = storeContract(world, contract, name, extraData); + await saveContract(world, contract, name, extraData); + + return world; +} diff --git a/scenario/src/Parser.ts b/scenario/src/Parser.ts new file mode 100644 index 000000000..928c0c976 --- /dev/null +++ b/scenario/src/Parser.ts @@ -0,0 +1,3210 @@ +// tslint:disable:only-arrow-functions +// tslint:disable:object-literal-shorthand +// tslint:disable:trailing-comma +// tslint:disable:object-literal-sort-keys +// tslint:disable:one-variable-per-declaration +// tslint:disable:max-line-length +// tslint:disable:no-consecutive-blank-lines +// tslint:disable:align + + +// Generated by PEG.js v. 0.10.0 (ts-pegjs plugin v. 0.2.2 ) +// +// https://pegjs.org/ https://github.com/metadevpro/ts-pegjs + +"use strict"; + +export interface IFilePosition { + offset: number; + line: number; + column: number; +} + +export interface IFileRange { + start: IFilePosition; + end: IFilePosition; +} + +export interface ILiteralExpectation { + type: "literal"; + text: string; + ignoreCase: boolean; +} + +export interface IClassParts extends Array {} + +export interface IClassExpectation { + type: "class"; + parts: IClassParts; + inverted: boolean; + ignoreCase: boolean; +} + +export interface IAnyExpectation { + type: "any"; +} + +export interface IEndExpectation { + type: "end"; +} + +export interface IOtherExpectation { + type: "other"; + description: string; +} + +export type Expectation = ILiteralExpectation | IClassExpectation | IAnyExpectation | IEndExpectation | IOtherExpectation; + +export class SyntaxError extends Error { + public static buildMessage(expected: Expectation[], found: string | null) { + function hex(ch: string): string { + return ch.charCodeAt(0).toString(16).toUpperCase(); + } + + function literalEscape(s: string): string { + return s + .replace(/\\/g, "\\\\") + .replace(/"/g, "\\\"") + .replace(/\0/g, "\\0") + .replace(/\t/g, "\\t") + .replace(/\n/g, "\\n") + .replace(/\r/g, "\\r") + .replace(/[\x00-\x0F]/g, (ch) => "\\x0" + hex(ch) ) + .replace(/[\x10-\x1F\x7F-\x9F]/g, (ch) => "\\x" + hex(ch) ); + } + + function classEscape(s: string): string { + return s + .replace(/\\/g, "\\\\") + .replace(/\]/g, "\\]") + .replace(/\^/g, "\\^") + .replace(/-/g, "\\-") + .replace(/\0/g, "\\0") + .replace(/\t/g, "\\t") + .replace(/\n/g, "\\n") + .replace(/\r/g, "\\r") + .replace(/[\x00-\x0F]/g, (ch) => "\\x0" + hex(ch) ) + .replace(/[\x10-\x1F\x7F-\x9F]/g, (ch) => "\\x" + hex(ch) ); + } + + function describeExpectation(expectation: Expectation) { + switch (expectation.type) { + case "literal": + return "\"" + literalEscape(expectation.text) + "\""; + case "class": + const escapedParts = expectation.parts.map((part) => { + return Array.isArray(part) + ? classEscape(part[0] as string) + "-" + classEscape(part[1] as string) + : classEscape(part); + }); + + return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]"; + case "any": + return "any character"; + case "end": + return "end of input"; + case "other": + return expectation.description; + } + } + + function describeExpected(expected1: Expectation[]) { + const descriptions = expected1.map(describeExpectation); + let i; + let j; + + descriptions.sort(); + + if (descriptions.length > 0) { + for (i = 1, j = 1; i < descriptions.length; i++) { + if (descriptions[i - 1] !== descriptions[i]) { + descriptions[j] = descriptions[i]; + j++; + } + } + descriptions.length = j; + } + + switch (descriptions.length) { + case 1: + return descriptions[0]; + + case 2: + return descriptions[0] + " or " + descriptions[1]; + + default: + return descriptions.slice(0, -1).join(", ") + + ", or " + + descriptions[descriptions.length - 1]; + } + } + + function describeFound(found1: string | null) { + return found1 ? "\"" + literalEscape(found1) + "\"" : "end of input"; + } + + return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found."; + } + + public message: string; + public expected: Expectation[]; + public found: string | null; + public location: IFileRange; + public name: string; + + constructor(message: string, expected: Expectation[], found: string | null, location: IFileRange) { + super(); + this.message = message; + this.expected = expected; + this.found = found; + this.location = location; + this.name = "SyntaxError"; + + if (typeof (Error as any).captureStackTrace === "function") { + (Error as any).captureStackTrace(this, SyntaxError); + } + } +} + +export interface ICached { + nextPos: number; + result: any; +} + +function peg$parse(input: string, options?: IParseOptions) { + options = options !== undefined ? options : {}; + + const peg$FAILED = {}; + + const peg$startRuleFunctions: {[id: string]: any} = { tests: peg$parsetests, step: peg$parsestep, macros: peg$parsemacros }; + let peg$startRuleFunction: () => any = peg$parsetests; + + const peg$c0 = function(head: any, t: any) { return t; }; + const peg$c1 = function(head: any, tail: any) { return tail.reduce((acc, el) => addTopLevelEl(acc, el), addTopLevelEl({macros: {}, tests: {}}, head)); }; + const peg$c2 = function(values: any) { return values !== null ? values.tests : {}; }; + const peg$c3 = function(values: any) { return values !== null ? values.macros : {}; }; + const peg$c4 = "Test"; + const peg$c5 = peg$literalExpectation("Test", false); + const peg$c6 = function(name: any, steps: any) { return {type: 'test', test: getString(name), steps: steps}; }; + const peg$c7 = "GasTest"; + const peg$c8 = peg$literalExpectation("GasTest", false); + const peg$c9 = function(name: any, steps: any) { return {type: 'test', test: getString(name), steps: ["Gas"].concat(steps)}; }; + const peg$c10 = "Pending"; + const peg$c11 = peg$literalExpectation("Pending", false); + const peg$c12 = function(name: any, steps: any) { return {type: 'test', test: getString(name), steps: ["Pending"].concat(steps)}; }; + const peg$c13 = "Only"; + const peg$c14 = peg$literalExpectation("Only", false); + const peg$c15 = function(name: any, steps: any) { return {type: 'test', test: getString(name), steps: ["Only"].concat(steps)}; }; + const peg$c16 = "Skip"; + const peg$c17 = peg$literalExpectation("Skip", false); + const peg$c18 = function(name: any, steps: any) { return {type: 'test', test: getString(name), steps: ["Skip"].concat(steps)}; }; + const peg$c19 = "Macro"; + const peg$c20 = peg$literalExpectation("Macro", false); + const peg$c21 = function(name: any, args: any, steps: any) { return {type: 'macro', name: getString(name), args: args || [], steps: steps}; }; + const peg$c22 = function(head: any, tail: any) { return [head].concat(tail).filter((x) => !!x); }; + const peg$c23 = function(args: any) { return args !== null ? args.flat() : []; }; + const peg$c24 = "..."; + const peg$c25 = peg$literalExpectation("...", false); + const peg$c26 = "="; + const peg$c27 = peg$literalExpectation("=", false); + const peg$c28 = function(splat: any, arg: any, t: any) { return t; }; + const peg$c29 = function(splat: any, arg: any, def: any) { return { arg, def, splat }; }; + const peg$c30 = function(tokens: any) { return tokens !== null ? tokens.flat() : []; }; + const peg$c31 = function(head: any, step: any) { return step; }; + const peg$c32 = function(steps: any) { return steps !== null ? steps : []; }; + const peg$c33 = function(step: any) { return step; }; + const peg$c34 = function() { return null; }; + const peg$c35 = function(val: any) { return val; }; + const peg$c36 = function(head: any, value: any) { return value }; + const peg$c37 = function(head: any, tail: any) { return [head].concat(tail.flat(1)); }; + const peg$c38 = function(inner: any) { return [inner]; }; + const peg$c39 = function(inner: any) { return [["List"].concat((inner || []).flat())] }; + const peg$c40 = "--"; + const peg$c41 = peg$literalExpectation("--", false); + const peg$c42 = /^[^\n]/; + const peg$c43 = peg$classExpectation(["\n"], true, false); + const peg$c44 = "#"; + const peg$c45 = peg$literalExpectation("#", false); + const peg$c46 = ":"; + const peg$c47 = peg$literalExpectation(":", false); + const peg$c48 = function(token1: any, token2: any) { return {argName: token1, argValue: token2} }; + const peg$c49 = /^[A-Za-z0-9_]/; + const peg$c50 = peg$classExpectation([["A", "Z"], ["a", "z"], ["0", "9"], "_"], false, false); + const peg$c51 = function(t: any) { return t.join("") }; + const peg$c52 = "0x"; + const peg$c53 = peg$literalExpectation("0x", false); + const peg$c54 = /^[0-9a-fA-F]/; + const peg$c55 = peg$classExpectation([["0", "9"], ["a", "f"], ["A", "F"]], false, false); + const peg$c56 = function(hex: any) { return ["Hex", hex.flat().flat().join("")] }; + const peg$c57 = "-"; + const peg$c58 = peg$literalExpectation("-", false); + const peg$c59 = "+"; + const peg$c60 = peg$literalExpectation("+", false); + const peg$c61 = /^[0-9]/; + const peg$c62 = peg$classExpectation([["0", "9"]], false, false); + const peg$c63 = "."; + const peg$c64 = peg$literalExpectation(".", false); + const peg$c65 = "e"; + const peg$c66 = peg$literalExpectation("e", false); + const peg$c67 = function(n: any) { return ["Exactly", n.flat().flat().join("")] }; + const peg$c68 = function(head: any, tail: any) { return [head].concat(tail.flat()); }; + const peg$c69 = "("; + const peg$c70 = peg$literalExpectation("(", false); + const peg$c71 = ")"; + const peg$c72 = peg$literalExpectation(")", false); + const peg$c73 = "["; + const peg$c74 = peg$literalExpectation("[", false); + const peg$c75 = "]"; + const peg$c76 = peg$literalExpectation("]", false); + const peg$c77 = "\r"; + const peg$c78 = peg$literalExpectation("\r", false); + const peg$c79 = "\n"; + const peg$c80 = peg$literalExpectation("\n", false); + const peg$c81 = "\t"; + const peg$c82 = peg$literalExpectation("\t", false); + const peg$c83 = " "; + const peg$c84 = peg$literalExpectation(" ", false); + const peg$c85 = "\\"; + const peg$c86 = peg$literalExpectation("\\", false); + const peg$c87 = peg$otherExpectation("whitespace"); + const peg$c88 = /^[ \t]/; + const peg$c89 = peg$classExpectation([" ", "\t"], false, false); + const peg$c90 = /^[ \t\r\n]/; + const peg$c91 = peg$classExpectation([" ", "\t", "\r", "\n"], false, false); + const peg$c92 = peg$otherExpectation("string"); + const peg$c93 = function(chars: any) { return ["String", chars.join("")]; }; + const peg$c94 = "\""; + const peg$c95 = peg$literalExpectation("\"", false); + const peg$c96 = "/"; + const peg$c97 = peg$literalExpectation("/", false); + const peg$c98 = "b"; + const peg$c99 = peg$literalExpectation("b", false); + const peg$c100 = function() { return "\b"; }; + const peg$c101 = "f"; + const peg$c102 = peg$literalExpectation("f", false); + const peg$c103 = function() { return "\f"; }; + const peg$c104 = "n"; + const peg$c105 = peg$literalExpectation("n", false); + const peg$c106 = function() { return "\n"; }; + const peg$c107 = "r"; + const peg$c108 = peg$literalExpectation("r", false); + const peg$c109 = function() { return "\r"; }; + const peg$c110 = "t"; + const peg$c111 = peg$literalExpectation("t", false); + const peg$c112 = function() { return "\t"; }; + const peg$c113 = "u"; + const peg$c114 = peg$literalExpectation("u", false); + const peg$c115 = function(digits: any) { + return String.fromCharCode(parseInt(digits, 16)); + }; + const peg$c116 = function(sequence: any) { return sequence; }; + const peg$c117 = /^[^\0-\x1F"\\]/; + const peg$c118 = peg$classExpectation([["\0", "\x1F"], "\"", "\\"], true, false); + const peg$c119 = /^[0-9a-f]/i; + const peg$c120 = peg$classExpectation([["0", "9"], ["a", "f"]], false, true); + + let peg$currPos = 0; + let peg$savedPos = 0; + const peg$posDetailsCache = [{ line: 1, column: 1 }]; + let peg$maxFailPos = 0; + let peg$maxFailExpected: any[] = []; + let peg$silentFails = 0; + + const peg$resultsCache: {[id: number]: ICached} = {}; + + let peg$result; + + if (options.startRule !== undefined) { + if (!(options.startRule in peg$startRuleFunctions)) { + throw new Error("Can't start parsing from rule \"" + options.startRule + "\"."); + } + + peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; + } + + function text(): string { + return input.substring(peg$savedPos, peg$currPos); + } + + function location(): IFileRange { + return peg$computeLocation(peg$savedPos, peg$currPos); + } + + function expected(description: string, location1?: IFileRange) { + location1 = location1 !== undefined + ? location1 + : peg$computeLocation(peg$savedPos, peg$currPos); + + throw peg$buildStructuredError( + [peg$otherExpectation(description)], + input.substring(peg$savedPos, peg$currPos), + location1 + ); + } + + function error(message: string, location1?: IFileRange) { + location1 = location1 !== undefined + ? location1 + : peg$computeLocation(peg$savedPos, peg$currPos); + + throw peg$buildSimpleError(message, location1); + } + + function peg$literalExpectation(text1: string, ignoreCase: boolean): ILiteralExpectation { + return { type: "literal", text: text1, ignoreCase: ignoreCase }; + } + + function peg$classExpectation(parts: IClassParts, inverted: boolean, ignoreCase: boolean): IClassExpectation { + return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase }; + } + + function peg$anyExpectation(): IAnyExpectation { + return { type: "any" }; + } + + function peg$endExpectation(): IEndExpectation { + return { type: "end" }; + } + + function peg$otherExpectation(description: string): IOtherExpectation { + return { type: "other", description: description }; + } + + function peg$computePosDetails(pos: number) { + let details = peg$posDetailsCache[pos]; + let p; + + if (details) { + return details; + } else { + p = pos - 1; + while (!peg$posDetailsCache[p]) { + p--; + } + + details = peg$posDetailsCache[p]; + details = { + line: details.line, + column: details.column + }; + + while (p < pos) { + if (input.charCodeAt(p) === 10) { + details.line++; + details.column = 1; + } else { + details.column++; + } + + p++; + } + + peg$posDetailsCache[pos] = details; + + return details; + } + } + + function peg$computeLocation(startPos: number, endPos: number): IFileRange { + const startPosDetails = peg$computePosDetails(startPos); + const endPosDetails = peg$computePosDetails(endPos); + + return { + start: { + offset: startPos, + line: startPosDetails.line, + column: startPosDetails.column + }, + end: { + offset: endPos, + line: endPosDetails.line, + column: endPosDetails.column + } + }; + } + + function peg$fail(expected1: Expectation) { + if (peg$currPos < peg$maxFailPos) { return; } + + if (peg$currPos > peg$maxFailPos) { + peg$maxFailPos = peg$currPos; + peg$maxFailExpected = []; + } + + peg$maxFailExpected.push(expected1); + } + + function peg$buildSimpleError(message: string, location1: IFileRange) { + return new SyntaxError(message, [], "", location1); + } + + function peg$buildStructuredError(expected1: Expectation[], found: string | null, location1: IFileRange) { + return new SyntaxError( + SyntaxError.buildMessage(expected1, found), + expected1, + found, + location1 + ); + } + + function peg$parsetests(): any { + let s0, s1, s2, s3, s4, s5, s6; + + const key = peg$currPos * 38 + 0; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$currPos; + s2 = peg$parsetop_level_el(); + if (s2 !== peg$FAILED) { + s3 = []; + s4 = peg$currPos; + s5 = peg$parseline_separator(); + if (s5 !== peg$FAILED) { + s6 = peg$parsetop_level_el(); + if (s6 !== peg$FAILED) { + peg$savedPos = s4; + s5 = peg$c0(s2, s6); + s4 = s5; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$currPos; + s5 = peg$parseline_separator(); + if (s5 !== peg$FAILED) { + s6 = peg$parsetop_level_el(); + if (s6 !== peg$FAILED) { + peg$savedPos = s4; + s5 = peg$c0(s2, s6); + s4 = s5; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s1; + s2 = peg$c1(s2, s3); + s1 = s2; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + s2 = peg$parsefull_ws(); + if (s2 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c2(s1); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsemacros(): any { + let s0, s1, s2, s3, s4, s5, s6; + + const key = peg$currPos * 38 + 1; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$currPos; + s2 = peg$parsetop_level_el(); + if (s2 !== peg$FAILED) { + s3 = []; + s4 = peg$currPos; + s5 = peg$parseline_separator(); + if (s5 !== peg$FAILED) { + s6 = peg$parsetop_level_el(); + if (s6 !== peg$FAILED) { + peg$savedPos = s4; + s5 = peg$c0(s2, s6); + s4 = s5; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$currPos; + s5 = peg$parseline_separator(); + if (s5 !== peg$FAILED) { + s6 = peg$parsetop_level_el(); + if (s6 !== peg$FAILED) { + peg$savedPos = s4; + s5 = peg$c0(s2, s6); + s4 = s5; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s1; + s2 = peg$c1(s2, s3); + s1 = s2; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + s2 = peg$parsefull_ws(); + if (s2 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c3(s1); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsetop_level_el(): any { + let s0; + + const key = peg$currPos * 38 + 2; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$parsetest(); + if (s0 === peg$FAILED) { + s0 = peg$parsemacro(); + if (s0 === peg$FAILED) { + s0 = peg$parsegastest(); + if (s0 === peg$FAILED) { + s0 = peg$parsepending(); + if (s0 === peg$FAILED) { + s0 = peg$parseonly(); + if (s0 === peg$FAILED) { + s0 = peg$parseskip(); + } + } + } + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsetest(): any { + let s0, s1, s2, s3, s4, s5, s6, s7; + + const key = peg$currPos * 38 + 3; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsefull_ws(); + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + if (input.substr(peg$currPos, 4) === peg$c4) { + s2 = peg$c4; + peg$currPos += 4; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c5); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + s4 = peg$parsestring(); + if (s4 !== peg$FAILED) { + s5 = peg$parsews(); + if (s5 !== peg$FAILED) { + s6 = peg$parseline_separator(); + if (s6 !== peg$FAILED) { + s7 = peg$parsesteps(); + if (s7 === peg$FAILED) { + s7 = null; + } + if (s7 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c6(s4, s7); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsegastest(): any { + let s0, s1, s2, s3, s4, s5, s6, s7; + + const key = peg$currPos * 38 + 4; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsefull_ws(); + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + if (input.substr(peg$currPos, 7) === peg$c7) { + s2 = peg$c7; + peg$currPos += 7; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c8); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + s4 = peg$parsestring(); + if (s4 !== peg$FAILED) { + s5 = peg$parsews(); + if (s5 !== peg$FAILED) { + s6 = peg$parseline_separator(); + if (s6 !== peg$FAILED) { + s7 = peg$parsesteps(); + if (s7 === peg$FAILED) { + s7 = null; + } + if (s7 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c9(s4, s7); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsepending(): any { + let s0, s1, s2, s3, s4, s5, s6, s7; + + const key = peg$currPos * 38 + 5; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsefull_ws(); + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + if (input.substr(peg$currPos, 7) === peg$c10) { + s2 = peg$c10; + peg$currPos += 7; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c11); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + s4 = peg$parsestring(); + if (s4 !== peg$FAILED) { + s5 = peg$parsews(); + if (s5 !== peg$FAILED) { + s6 = peg$parseline_separator(); + if (s6 !== peg$FAILED) { + s7 = peg$parsesteps(); + if (s7 === peg$FAILED) { + s7 = null; + } + if (s7 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c12(s4, s7); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseonly(): any { + let s0, s1, s2, s3, s4, s5, s6, s7; + + const key = peg$currPos * 38 + 6; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsefull_ws(); + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + if (input.substr(peg$currPos, 4) === peg$c13) { + s2 = peg$c13; + peg$currPos += 4; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c14); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + s4 = peg$parsestring(); + if (s4 !== peg$FAILED) { + s5 = peg$parsews(); + if (s5 !== peg$FAILED) { + s6 = peg$parseline_separator(); + if (s6 !== peg$FAILED) { + s7 = peg$parsesteps(); + if (s7 === peg$FAILED) { + s7 = null; + } + if (s7 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c15(s4, s7); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseskip(): any { + let s0, s1, s2, s3, s4, s5, s6, s7; + + const key = peg$currPos * 38 + 7; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsefull_ws(); + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + if (input.substr(peg$currPos, 4) === peg$c16) { + s2 = peg$c16; + peg$currPos += 4; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c17); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + s4 = peg$parsestring(); + if (s4 !== peg$FAILED) { + s5 = peg$parsews(); + if (s5 !== peg$FAILED) { + s6 = peg$parseline_separator(); + if (s6 !== peg$FAILED) { + s7 = peg$parsesteps(); + if (s7 === peg$FAILED) { + s7 = null; + } + if (s7 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c18(s4, s7); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsemacro(): any { + let s0, s1, s2, s3, s4, s5, s6, s7, s8; + + const key = peg$currPos * 38 + 8; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsefull_ws(); + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + if (input.substr(peg$currPos, 5) === peg$c19) { + s2 = peg$c19; + peg$currPos += 5; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c20); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + s4 = peg$parsetoken(); + if (s4 !== peg$FAILED) { + s5 = peg$parsews(); + if (s5 !== peg$FAILED) { + s6 = peg$parseargs(); + if (s6 === peg$FAILED) { + s6 = null; + } + if (s6 !== peg$FAILED) { + s7 = peg$parseline_separator(); + if (s7 !== peg$FAILED) { + s8 = peg$parsesteps(); + if (s8 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c21(s4, s6, s8); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseargs(): any { + let s0, s1, s2, s3, s4, s5, s6; + + const key = peg$currPos * 38 + 9; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$currPos; + s2 = peg$parsearg(); + if (s2 !== peg$FAILED) { + s3 = []; + s4 = peg$currPos; + s5 = peg$parsews(); + if (s5 !== peg$FAILED) { + s6 = peg$parseargs(); + if (s6 !== peg$FAILED) { + peg$savedPos = s4; + s5 = peg$c0(s2, s6); + s4 = s5; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$currPos; + s5 = peg$parsews(); + if (s5 !== peg$FAILED) { + s6 = peg$parseargs(); + if (s6 !== peg$FAILED) { + peg$savedPos = s4; + s5 = peg$c0(s2, s6); + s4 = s5; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s1; + s2 = peg$c22(s2, s3); + s1 = s2; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c23(s1); + } + s0 = s1; + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsearg(): any { + let s0, s1, s2, s3, s4, s5, s6, s7; + + const key = peg$currPos * 38 + 10; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + if (input.substr(peg$currPos, 3) === peg$c24) { + s1 = peg$c24; + peg$currPos += 3; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c25); } + } + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + s2 = peg$parsetoken(); + if (s2 !== peg$FAILED) { + s3 = peg$currPos; + s4 = peg$parsews(); + if (s4 === peg$FAILED) { + s4 = null; + } + if (s4 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 61) { + s5 = peg$c26; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c27); } + } + if (s5 !== peg$FAILED) { + s6 = peg$parsetoken(); + if (s6 !== peg$FAILED) { + s7 = peg$parsews(); + if (s7 === peg$FAILED) { + s7 = null; + } + if (s7 !== peg$FAILED) { + peg$savedPos = s3; + s4 = peg$c28(s1, s2, s6); + s3 = s4; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + if (s3 === peg$FAILED) { + s3 = null; + } + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c29(s1, s2, s3); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsetoken_set(): any { + let s0, s1, s2, s3, s4, s5, s6; + + const key = peg$currPos * 38 + 11; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$currPos; + s2 = peg$parsetoken(); + if (s2 !== peg$FAILED) { + s3 = []; + s4 = peg$currPos; + s5 = peg$parsews(); + if (s5 !== peg$FAILED) { + s6 = peg$parsetoken_set(); + if (s6 !== peg$FAILED) { + peg$savedPos = s4; + s5 = peg$c0(s2, s6); + s4 = s5; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$currPos; + s5 = peg$parsews(); + if (s5 !== peg$FAILED) { + s6 = peg$parsetoken_set(); + if (s6 !== peg$FAILED) { + peg$savedPos = s4; + s5 = peg$c0(s2, s6); + s4 = s5; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s1; + s2 = peg$c22(s2, s3); + s1 = s2; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c30(s1); + } + s0 = s1; + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsesteps(): any { + let s0, s1, s2, s3, s4, s5, s6; + + const key = peg$currPos * 38 + 12; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$currPos; + s2 = peg$parsefull_expr(); + if (s2 !== peg$FAILED) { + s3 = []; + s4 = peg$currPos; + s5 = peg$parseline_separator(); + if (s5 !== peg$FAILED) { + s6 = peg$parsefull_expr(); + if (s6 !== peg$FAILED) { + peg$savedPos = s4; + s5 = peg$c31(s2, s6); + s4 = s5; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$currPos; + s5 = peg$parseline_separator(); + if (s5 !== peg$FAILED) { + s6 = peg$parsefull_expr(); + if (s6 !== peg$FAILED) { + peg$savedPos = s4; + s5 = peg$c31(s2, s6); + s4 = s5; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s1; + s2 = peg$c22(s2, s3); + s1 = s2; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c32(s1); + } + s0 = s1; + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsefull_expr(): any { + let s0, s1, s2; + + const key = peg$currPos * 38 + 13; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsetab_separator(); + if (s1 !== peg$FAILED) { + s2 = peg$parsestep(); + if (s2 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c33(s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parsecomment(); + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c34(); + } + s0 = s1; + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parsetab_separator(); + if (s1 !== peg$FAILED) { + s2 = peg$parsews(); + if (s2 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c34(); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsestep(): any { + let s0, s1, s2; + + const key = peg$currPos * 38 + 14; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parseexpr(); + if (s1 !== peg$FAILED) { + s2 = peg$parsecomment(); + if (s2 === peg$FAILED) { + s2 = null; + } + if (s2 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c35(s1); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parsecomment(); + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c34(); + } + s0 = s1; + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parsetab_separator(); + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + s2 = peg$parsews(); + if (s2 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c34(); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseexpr(): any { + let s0, s1, s2, s3, s4, s5, s6; + + const key = peg$currPos * 38 + 15; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsetoken(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parsews(); + if (s4 !== peg$FAILED) { + s5 = peg$parsecontinuation(); + if (s5 === peg$FAILED) { + s5 = null; + } + if (s5 !== peg$FAILED) { + s6 = peg$parseexpr(); + if (s6 !== peg$FAILED) { + peg$savedPos = s3; + s4 = peg$c36(s1, s6); + s3 = s4; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parsews(); + if (s4 !== peg$FAILED) { + s5 = peg$parsecontinuation(); + if (s5 === peg$FAILED) { + s5 = null; + } + if (s5 !== peg$FAILED) { + s6 = peg$parseexpr(); + if (s6 !== peg$FAILED) { + peg$savedPos = s3; + s4 = peg$c36(s1, s6); + s3 = s4; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + if (s2 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c37(s1, s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parsebegin_compound(); + if (s1 !== peg$FAILED) { + s2 = peg$parseexpr(); + if (s2 !== peg$FAILED) { + s3 = peg$parseend_compound(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c38(s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parsebegin_list(); + if (s1 !== peg$FAILED) { + s2 = peg$parselist_inner(); + if (s2 === peg$FAILED) { + s2 = null; + } + if (s2 !== peg$FAILED) { + s3 = peg$parseend_list(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c39(s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsecomment(): any { + let s0, s1, s2, s3, s4; + + const key = peg$currPos * 38 + 16; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsews(); + if (s1 !== peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c40) { + s2 = peg$c40; + peg$currPos += 2; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c41); } + } + if (s2 !== peg$FAILED) { + s3 = []; + if (peg$c42.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c43); } + } + while (s4 !== peg$FAILED) { + s3.push(s4); + if (peg$c42.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c43); } + } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c34(); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parsews(); + if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 35) { + s2 = peg$c44; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c45); } + } + if (s2 !== peg$FAILED) { + s3 = []; + if (peg$c42.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c43); } + } + while (s4 !== peg$FAILED) { + s3.push(s4); + if (peg$c42.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c43); } + } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c34(); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsetoken(): any { + let s0, s1, s2, s3; + + const key = peg$currPos * 38 + 17; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsesimple_token(); + if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 58) { + s2 = peg$c46; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c47); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsesimple_token(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c48(s1, s3); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$parsesimple_token(); + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsesimple_token(): any { + let s0, s1, s2; + + const key = peg$currPos * 38 + 18; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$parsehex(); + if (s0 === peg$FAILED) { + s0 = peg$parsenumber(); + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = []; + if (peg$c49.test(input.charAt(peg$currPos))) { + s2 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c50); } + } + if (s2 !== peg$FAILED) { + while (s2 !== peg$FAILED) { + s1.push(s2); + if (peg$c49.test(input.charAt(peg$currPos))) { + s2 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c50); } + } + } + } else { + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c51(s1); + } + s0 = s1; + if (s0 === peg$FAILED) { + s0 = peg$parsestring(); + } + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsehex(): any { + let s0, s1, s2, s3, s4; + + const key = peg$currPos * 38 + 19; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$currPos; + if (input.substr(peg$currPos, 2) === peg$c52) { + s2 = peg$c52; + peg$currPos += 2; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c53); } + } + if (s2 !== peg$FAILED) { + s3 = []; + if (peg$c54.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c55); } + } + if (s4 !== peg$FAILED) { + while (s4 !== peg$FAILED) { + s3.push(s4); + if (peg$c54.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c55); } + } + } + } else { + s3 = peg$FAILED; + } + if (s3 !== peg$FAILED) { + s2 = [s2, s3]; + s1 = s2; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c56(s1); + } + s0 = s1; + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsenumber(): any { + let s0, s1, s2, s3, s4, s5, s6, s7, s8, s9; + + const key = peg$currPos * 38 + 20; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 45) { + s2 = peg$c57; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c58); } + } + if (s2 === peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 43) { + s2 = peg$c59; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c60); } + } + } + if (s2 === peg$FAILED) { + s2 = null; + } + if (s2 !== peg$FAILED) { + s3 = []; + if (peg$c61.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c62); } + } + if (s4 !== peg$FAILED) { + while (s4 !== peg$FAILED) { + s3.push(s4); + if (peg$c61.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c62); } + } + } + } else { + s3 = peg$FAILED; + } + if (s3 !== peg$FAILED) { + s4 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 46) { + s5 = peg$c63; + peg$currPos++; + } else { + s5 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c64); } + } + if (s5 !== peg$FAILED) { + s6 = []; + if (peg$c61.test(input.charAt(peg$currPos))) { + s7 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s7 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c62); } + } + if (s7 !== peg$FAILED) { + while (s7 !== peg$FAILED) { + s6.push(s7); + if (peg$c61.test(input.charAt(peg$currPos))) { + s7 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s7 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c62); } + } + } + } else { + s6 = peg$FAILED; + } + if (s6 !== peg$FAILED) { + s5 = [s5, s6]; + s4 = s5; + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + } else { + peg$currPos = s4; + s4 = peg$FAILED; + } + if (s4 === peg$FAILED) { + s4 = null; + } + if (s4 !== peg$FAILED) { + s5 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 101) { + s6 = peg$c65; + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c66); } + } + if (s6 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 45) { + s7 = peg$c57; + peg$currPos++; + } else { + s7 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c58); } + } + if (s7 === peg$FAILED) { + s7 = null; + } + if (s7 !== peg$FAILED) { + s8 = []; + if (peg$c61.test(input.charAt(peg$currPos))) { + s9 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s9 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c62); } + } + if (s9 !== peg$FAILED) { + while (s9 !== peg$FAILED) { + s8.push(s9); + if (peg$c61.test(input.charAt(peg$currPos))) { + s9 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s9 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c62); } + } + } + } else { + s8 = peg$FAILED; + } + if (s8 !== peg$FAILED) { + s6 = [s6, s7, s8]; + s5 = s6; + } else { + peg$currPos = s5; + s5 = peg$FAILED; + } + } else { + peg$currPos = s5; + s5 = peg$FAILED; + } + } else { + peg$currPos = s5; + s5 = peg$FAILED; + } + if (s5 === peg$FAILED) { + s5 = null; + } + if (s5 !== peg$FAILED) { + s2 = [s2, s3, s4, s5]; + s1 = s2; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c67(s1); + } + s0 = s1; + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parselist_inner(): any { + let s0, s1, s2, s3, s4, s5; + + const key = peg$currPos * 38 + 21; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parseexpr(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = peg$parsews(); + if (s4 === peg$FAILED) { + s4 = null; + } + if (s4 !== peg$FAILED) { + s5 = peg$parselist_inner(); + if (s5 !== peg$FAILED) { + peg$savedPos = s3; + s4 = peg$c36(s1, s5); + s3 = s4; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$parsews(); + if (s4 === peg$FAILED) { + s4 = null; + } + if (s4 !== peg$FAILED) { + s5 = peg$parselist_inner(); + if (s5 !== peg$FAILED) { + peg$savedPos = s3; + s4 = peg$c36(s1, s5); + s3 = s4; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + } + if (s2 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c68(s1, s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsebegin_compound(): any { + let s0, s1, s2, s3; + + const key = peg$currPos * 38 + 22; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsews(); + if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 40) { + s2 = peg$c69; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c70); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + s1 = [s1, s2, s3]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseend_compound(): any { + let s0, s1, s2, s3; + + const key = peg$currPos * 38 + 23; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsews(); + if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 41) { + s2 = peg$c71; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c72); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + s1 = [s1, s2, s3]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsebegin_list(): any { + let s0, s1, s2, s3; + + const key = peg$currPos * 38 + 24; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsews(); + if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 91) { + s2 = peg$c73; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c74); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + s1 = [s1, s2, s3]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseend_list(): any { + let s0, s1, s2, s3; + + const key = peg$currPos * 38 + 25; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsews(); + if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 93) { + s2 = peg$c75; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c76); } + } + if (s2 !== peg$FAILED) { + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + s1 = [s1, s2, s3]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseline_separator(): any { + let s0, s1, s2; + + const key = peg$currPos * 38 + 26; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 13) { + s1 = peg$c77; + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c78); } + } + if (s1 === peg$FAILED) { + s1 = null; + } + if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 10) { + s2 = peg$c79; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c80); } + } + if (s2 !== peg$FAILED) { + s1 = [s1, s2]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsetab_separator(): any { + let s0; + + const key = peg$currPos * 38 + 27; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + if (input.charCodeAt(peg$currPos) === 9) { + s0 = peg$c81; + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c82); } + } + if (s0 === peg$FAILED) { + if (input.substr(peg$currPos, 4) === peg$c83) { + s0 = peg$c83; + peg$currPos += 4; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c84); } + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsecontinuation(): any { + let s0, s1, s2, s3, s4; + + const key = peg$currPos * 38 + 28; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 92) { + s1 = peg$c85; + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c86); } + } + if (s1 !== peg$FAILED) { + s2 = peg$parseline_separator(); + if (s2 !== peg$FAILED) { + s3 = peg$parsetab_separator(); + if (s3 !== peg$FAILED) { + s4 = peg$parsetab_separator(); + if (s4 !== peg$FAILED) { + s1 = [s1, s2, s3, s4]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsews(): any { + let s0, s1; + + const key = peg$currPos * 38 + 29; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = []; + if (peg$c88.test(input.charAt(peg$currPos))) { + s1 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c89); } + } + while (s1 !== peg$FAILED) { + s0.push(s1); + if (peg$c88.test(input.charAt(peg$currPos))) { + s1 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c89); } + } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c87); } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsefull_ws(): any { + let s0, s1, s2; + + const key = peg$currPos * 38 + 30; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$currPos; + s1 = peg$parsecomment(); + if (s1 !== peg$FAILED) { + s2 = peg$parsefull_ws(); + if (s2 !== peg$FAILED) { + s1 = [s1, s2]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (peg$c90.test(input.charAt(peg$currPos))) { + s1 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c91); } + } + if (s1 !== peg$FAILED) { + s2 = peg$parsefull_ws(); + if (s2 === peg$FAILED) { + s2 = null; + } + if (s2 !== peg$FAILED) { + s1 = [s1, s2]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsestring(): any { + let s0, s1, s2, s3; + + const key = peg$currPos * 38 + 31; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + s1 = peg$parsequotation_mark(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$parsechar(); + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$parsechar(); + } + if (s2 !== peg$FAILED) { + s3 = peg$parsequotation_mark(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c93(s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c92); } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsechar(): any { + let s0, s1, s2, s3, s4, s5, s6, s7, s8, s9; + + const key = peg$currPos * 38 + 32; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$parseunescaped(); + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parseescape(); + if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 34) { + s2 = peg$c94; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c95); } + } + if (s2 === peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 92) { + s2 = peg$c85; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c86); } + } + if (s2 === peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 47) { + s2 = peg$c96; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c97); } + } + if (s2 === peg$FAILED) { + s2 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 98) { + s3 = peg$c98; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c99); } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s2; + s3 = peg$c100(); + } + s2 = s3; + if (s2 === peg$FAILED) { + s2 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 102) { + s3 = peg$c101; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c102); } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s2; + s3 = peg$c103(); + } + s2 = s3; + if (s2 === peg$FAILED) { + s2 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 110) { + s3 = peg$c104; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c105); } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s2; + s3 = peg$c106(); + } + s2 = s3; + if (s2 === peg$FAILED) { + s2 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 114) { + s3 = peg$c107; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c108); } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s2; + s3 = peg$c109(); + } + s2 = s3; + if (s2 === peg$FAILED) { + s2 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 116) { + s3 = peg$c110; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c111); } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s2; + s3 = peg$c112(); + } + s2 = s3; + if (s2 === peg$FAILED) { + s2 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 117) { + s3 = peg$c113; + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c114); } + } + if (s3 !== peg$FAILED) { + s4 = peg$currPos; + s5 = peg$currPos; + s6 = peg$parseHEXDIG(); + if (s6 !== peg$FAILED) { + s7 = peg$parseHEXDIG(); + if (s7 !== peg$FAILED) { + s8 = peg$parseHEXDIG(); + if (s8 !== peg$FAILED) { + s9 = peg$parseHEXDIG(); + if (s9 !== peg$FAILED) { + s6 = [s6, s7, s8, s9]; + s5 = s6; + } else { + peg$currPos = s5; + s5 = peg$FAILED; + } + } else { + peg$currPos = s5; + s5 = peg$FAILED; + } + } else { + peg$currPos = s5; + s5 = peg$FAILED; + } + } else { + peg$currPos = s5; + s5 = peg$FAILED; + } + if (s5 !== peg$FAILED) { + s4 = input.substring(s4, peg$currPos); + } else { + s4 = s5; + } + if (s4 !== peg$FAILED) { + peg$savedPos = s2; + s3 = peg$c115(s4); + s2 = s3; + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + } else { + peg$currPos = s2; + s2 = peg$FAILED; + } + } + } + } + } + } + } + } + } + if (s2 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c116(s2); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseescape(): any { + let s0; + + const key = peg$currPos * 38 + 33; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + if (input.charCodeAt(peg$currPos) === 92) { + s0 = peg$c85; + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c86); } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsequotation_mark(): any { + let s0; + + const key = peg$currPos * 38 + 34; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + if (input.charCodeAt(peg$currPos) === 34) { + s0 = peg$c94; + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c95); } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseunescaped(): any { + let s0; + + const key = peg$currPos * 38 + 35; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + if (peg$c117.test(input.charAt(peg$currPos))) { + s0 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c118); } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseDIGIT(): any { + let s0; + + const key = peg$currPos * 38 + 36; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + if (peg$c61.test(input.charAt(peg$currPos))) { + s0 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c62); } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseHEXDIG(): any { + let s0; + + const key = peg$currPos * 38 + 37; + const cached: ICached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + if (peg$c119.test(input.charAt(peg$currPos))) { + s0 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s0 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c120); } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + + if (!Array.prototype.flat) { + Object.defineProperty(Array.prototype, 'flat', { + configurable: true, + value: function flat (x) { + var depth = isNaN(arguments[0]) ? 1 : Number(arguments[0]); + + return depth ? Array.prototype.reduce.call(this, function (acc, cur) { + if (Array.isArray(cur)) { + acc.push.apply(acc, flat.call(cur, depth - 1)); + } else { + acc.push(cur); + } + + return acc; + }, []) : Array.prototype.slice.call(this); + }, + writable: true + }); + } + + function getString(str) { + let val; + if (Array.isArray(str)) { + if (str.length !== 2 || str[0] !== 'String') { + throw new Error(`Expected string, got ${str}`); + } + + val = str[1]; + } else { + val = str; + } + + if (typeof val !== 'string') { + throw new Error(`Expected string, got ${val} (${typeof val})`); + } + + return val; + } + + function expandEvent(macros, step) { + const [eventName, ...eventArgs] = step; + + if (macros[eventName]) { + let expanded = expandMacro(macros[eventName], eventArgs); + + // Recursively expand steps + return expanded.map(event => expandEvent(macros, event)).flat(); + } else { + return [step]; + } + } + + function getArgValues(eventArgs, macroArgs) { + const eventArgNameMap = {}; + const eventArgIndexed = new Array(); + const argValues = {}; + let usedNamedArg = false; + let usedSplat = false; + + eventArgs.forEach((eventArg) => { + if (eventArg.argName) { + const {argName, argValue} = eventArg; + + eventArgNameMap[argName] = argValue; + usedNamedArg = true; + } else { + if (usedNamedArg) { + throw new Error(`Cannot use positional arg after named arg in macro invokation ${JSON.stringify(eventArgs)} looking at ${eventArg.toString()}`); + } + + eventArgIndexed.push(eventArg); + } + }); + + macroArgs.forEach(({arg, def, splat}, argIndex) => { + if (usedSplat) { + throw new Error("Cannot have arg after splat arg"); + } + + let val; + if (eventArgNameMap[arg] !== undefined) { + val = eventArgNameMap[arg]; + } else if (splat) { + val = eventArgIndexed.slice(argIndex); // Clear out any remaining args + usedSplat = true; + } else if (eventArgIndexed[argIndex] !== undefined) { + val = eventArgIndexed[argIndex]; + } else if (def !== undefined) { + val = def; + } else { + throw new Error("Macro cannot find arg value for " + arg); + } + argValues[arg] = val; + }); + + return argValues; + } + + function expandMacro(macro, eventArgs) { + const argValues = getArgValues(eventArgs, macro.args); + + function expandStep(step) { + return step.map((token) => { + if (argValues[token] !== undefined) { + return argValues[token]; + } else { + if (Array.isArray(token)) { + return expandStep(token); + } else { + return token; + } + } + }); + }; + + return macro.steps.map(expandStep); + } + + function addTopLevelEl(state, el) { + const macros = state.macros; + const tests = state.tests; + const pending = state.pending; + + switch (el.type) { + case 'macro': + const macro = {[el.name]: {args: el.args, steps: el.steps}}; + + return { + tests: tests, + macros: ({...macros, ...macro}) + }; + case 'test': + const steps = el.steps; + const expandedSteps = steps.map((step) => { + return expandEvent(macros, step) + }).flat(); + + const test = {[el.test]: expandedSteps}; + + return { + tests: {...tests, ...test}, + macros: macros + } + } + } + + + peg$result = peg$startRuleFunction(); + + if (peg$result !== peg$FAILED && peg$currPos === input.length) { + return peg$result; + } else { + if (peg$result !== peg$FAILED && peg$currPos < input.length) { + peg$fail(peg$endExpectation()); + } + + throw peg$buildStructuredError( + peg$maxFailExpected, + peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null, + peg$maxFailPos < input.length + ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) + : peg$computeLocation(peg$maxFailPos, peg$maxFailPos) + ); + } +} + +export interface IParseOptions { + filename?: string; + startRule?: string; + tracer?: any; + [key: string]: any; +} +export type ParseFunction = (input: string, options?: IParseOptions) => any; +export const parse: ParseFunction = peg$parse; + diff --git a/scenario/src/Printer.ts b/scenario/src/Printer.ts new file mode 100644 index 000000000..478bbfc69 --- /dev/null +++ b/scenario/src/Printer.ts @@ -0,0 +1,120 @@ +import {Value} from './Value'; +import {Action} from './Action'; +import {EventProcessingError} from './CoreEvent' +import {formatEvent} from './Formatter'; + +import * as readline from 'readline'; + +export interface Printer { + printLine(str: string): void + printMarkdown(str: string): void + printValue(val: Value): void + printError(err: Error): void + printAction(action: Action): void +} + +export class CallbackPrinter implements Printer { + callback: (message: any, format: object) => void + + constructor(callback: (message: string) => void) { + this.callback = callback; + } + + printLine(str: string): void { + this.callback(str, {}); + } + + printMarkdown(str: string): void { + this.callback(str, {markdown: true}); + } + + printValue(val: Value): void { + this.callback(val.toString(), {value: true}); + } + + printError(err: Error): void { + if (process.env['verbose']) { + this.callback(err, {error: true}); + } + + this.callback(`Error: ${err.toString()}`, {error: true}); + } + + printAction(action: Action): void { + // Do nothing + } +} + +export class ConsolePrinter implements Printer { + verbose: boolean + + constructor(verbose: boolean) { + this.verbose = verbose; + } + + printLine(str: string): void { + console.log(str); + } + + printMarkdown(str: string): void { + console.log(str); + } + + printValue(val: Value): void { + console.log(val.toString()); + } + + printError(err: Error): void { + if (this.verbose) { + console.log(err); + } + + console.log(`Error: ${err.toString()}`); + } + + printAction(action: Action): void { + if (this.verbose) { + console.log(`Action: ${action.log}`); + } + } +} + +export class ReplPrinter implements Printer { + rl : readline.Interface; + verbose : boolean + + constructor(rl: readline.Interface, verbose: boolean) { + this.rl = rl; + this.verbose = verbose; + } + + printLine(str: string): void { + console.log(`${str}`); + } + + printMarkdown(str: string): void { + console.log(`${str}`); + } + + printValue(val: Value): void { + console.log(val.toString()); + } + + printError(err: Error): void { + if (this.verbose) { + console.log(err); + } + + if (err instanceof EventProcessingError) { + console.log(`Event Processing Error:`); + console.log(`\t${err.error.toString()}`); + console.log(`\twhen processing event \`${formatEvent(err.event)}\``); + } else { + console.log(`Error: ${err.toString()}`); + } + } + + printAction(action: Action): void { + console.log(`Action: ${action.log}`); + } +} diff --git a/scenario/src/Repl.d.ts b/scenario/src/Repl.d.ts new file mode 100644 index 000000000..a4a22f456 --- /dev/null +++ b/scenario/src/Repl.d.ts @@ -0,0 +1,9 @@ +import {Artifacts} from './Artifact'; +import {Web3} from './Web3'; + +declare namespace NodeJS { + interface Global { + Web3: Web3 + Artifacts: Artifacts + } +} diff --git a/scenario/src/Repl.ts b/scenario/src/Repl.ts new file mode 100644 index 000000000..3bc297ad6 --- /dev/null +++ b/scenario/src/Repl.ts @@ -0,0 +1,168 @@ +import {ReplPrinter} from './Printer'; +import { + addInvariant, + initWorld, + IWeb3, + loadInvokationOpts, + loadDryRun, + loadSettings, + loadVerbose, + World +} from './World'; +import {Artifacts} from './Artifact'; +import {throwAssert} from './Assert'; +import {Macros} from './Macro'; +import {formatEvent} from './Formatter'; +import {complete} from './Completer'; +import {loadContracts} from './Networks'; +import {accountAliases, loadAccounts} from './Accounts'; +import {getNetworkPath} from './File'; +import {SuccessInvariant} from './Invariant/SuccessInvariant'; +import {createInterface} from './HistoricReadline'; +import {runCommand} from './Runner'; +import {parse} from './Parser'; +import Web3 from 'web3'; + +import * as fs from 'fs'; +import * as path from 'path'; + +const basePath = process.env.proj_root || process.cwd(); +const baseScenarioPath = path.join(basePath, 'spec', 'scenario'); + +declare var web3: IWeb3; +declare var artifacts: Artifacts; + +function questionPromise(rl): Promise { + return new Promise((resolve, reject) => { + rl.question(" > ", (command) => { + resolve(command); + }); + }); +} + +async function loop(world, rl, macros): Promise { + let command = await questionPromise(rl); + + try { + let newWorld = await runCommand(world, command, macros); + + return await loop(newWorld, rl, macros); + } catch (err) { + world.printer.printError(err); + return await loop(world, rl, macros); + } +} + +function loadEnvVars(): object { + return (process.env['env_vars'] || '').split(',').reduce((acc, keyValue) => { + if (keyValue.length === 0) { + return acc; + } else { + const [key, value] = keyValue.split('='); + + return { + ...acc, + [key]: value + }; + } + }, {}); +} + +async function repl(web3: IWeb3, artifacts: Artifacts): Promise { + // Uck, we need to load core macros :( + const coreMacros = fs.readFileSync(path.join(baseScenarioPath, 'CoreMacros'), 'utf8'); + + const macros = parse(coreMacros, {startRule: 'macros'}); + + let script = process.env['script']; + + let accounts: string[]; + + let network = process.env['network']; + + if (!network) { + throw new Error(`Missing required "network" env argument`); + } + + let world; + + let rl = await createInterface({ + input: process.stdin, + output: process.stdout, + completer: (line) => complete(world, macros, line), + path: getNetworkPath(basePath, network, '-history', null) + }); + + const verbose: boolean = !!process.env['verbose']; + let printer = new ReplPrinter(rl, verbose); + + // Uck, we have to load accounts first... + if (web3.currentProvider && web3.currentProvider.addresses && web3.currentProvider.addresses.length > 0) { + // We have a wallet provider + accounts = web3.currentProvider.addresses; + } else { + // Let's see if we have any unlocked accounts + accounts = await (new Web3(web3.currentProvider)).eth.personal.getAccounts(); + } + + let contractInfo: string[]; + world = await initWorld(throwAssert, printer, web3, artifacts, network, accounts, basePath); + [world, contractInfo] = await loadContracts(world); + world = loadInvokationOpts(world); + world = loadVerbose(world); + world = loadDryRun(world); + world = await loadSettings(world); + + printer.printLine(`Network: ${network}`); + + if (accounts.length > 0) { + printer.printLine(`Accounts:`); + accounts.forEach((account, i) => { + let aliases = world.settings.lookupAliases(account); + aliases = aliases.concat(accountAliases(i)); + + printer.printLine(`\t${account} (${aliases.join(',')})`) + }); + } + + if (contractInfo.length > 0) { + world.printer.printLine(`Contracts:`); + contractInfo.forEach((info) => world.printer.printLine(`\t${info}`)); + } + + printer.printLine(`Available macros: ${Object.keys(macros).toString()}`); + printer.printLine(``); + + if (script) { + printer.printLine(`Running script: ${script}...`); + const envVars = loadEnvVars(); + const scriptData: string = fs.readFileSync(script).toString(); + + if (Object.keys(envVars).length > 0) { + printer.printLine(`Env Vars:`); + } + + const replacedScript = Object.entries(envVars).reduce((data, [key, val]) => { + printer.printLine(`\t${key}: ${val}`); + + return data.split(`$${key}`).join(val); + }, scriptData); + + const finalScript = replacedScript.replace(new RegExp(/\$[\w_]+/, 'g'), 'Nothing'); + + return await finalScript.split("\n").reduce(async (acc, command) => { + return await runCommand(await acc, command, macros); + }, Promise.resolve(world)); + printer.printLine(`Script complete.`); + } else { + await loop(world, rl, macros); + } +} + +export = function(callback) { + repl(web3, artifacts).catch((err) => { + console.error("Fatal error"); + console.error(err); + callback(); + }).then(() => callback()); +} diff --git a/scenario/src/Runner.ts b/scenario/src/Runner.ts new file mode 100644 index 000000000..e5aac37e6 --- /dev/null +++ b/scenario/src/Runner.ts @@ -0,0 +1,20 @@ +import {World} from './World'; +import {parse} from './Parser'; +import {expandEvent, Macros} from './Macro'; +import {processEvents} from './CoreEvent' + +export async function runCommand(world: World, command: string, macros: Macros): Promise { + const trimmedCommand = command.trim(); + + const event = parse(trimmedCommand, {startRule: 'step'}); + + if (event === null) { + return world; + } else { + world.printer.printLine(`Command: ${trimmedCommand}`); + + let expanded = expandEvent(macros, event); + + return processEvents(world, expanded); + } +} diff --git a/scenario/src/Settings.ts b/scenario/src/Settings.ts new file mode 100644 index 000000000..ff82224f0 --- /dev/null +++ b/scenario/src/Settings.ts @@ -0,0 +1,75 @@ +import {getNetworkPath, readFile, writeFile} from './File'; + +export class Settings { + basePath: string | null + network: string | null + aliases: {[name: string]: string} + from: string | undefined + + constructor(basePath: string | null, network: string | null, aliases: {[name: string]: string}, from?: string) { + this.basePath = basePath; + this.network = network; + this.aliases = aliases; + this.from = from; + } + + static deserialize(basePath: string, network: string, data: string): Settings { + const {aliases} = JSON.parse(data); + + return new Settings(basePath, network, aliases); + } + + serialize(): string { + return JSON.stringify({ + aliases: this.aliases + }); + } + + static default(basePath: string | null, network: string | null): Settings { + return new Settings(basePath, network, {}); + } + + static getFilePath(basePath: string | null, network: string): string { + return getNetworkPath(basePath, network, '-settings'); + } + + static load(basePath: string, network: string): Promise { + return readFile(Settings.getFilePath(basePath, network), Settings.default(basePath, network), (data) => Settings.deserialize(basePath, network, data)); + } + + async save(): Promise { + if (this.network) { + return await writeFile(Settings.getFilePath(this.basePath, this.network), this.serialize()); + } + } + + lookupAlias(address: string): string { + let entry = Object.entries(this.aliases).find(([key, value]) => { + return value === address; + }); + + if (entry) { + return entry[0]; + } else { + return address; + } + } + + lookupAliases(address: string): string[] { + let entries = Object.entries(this.aliases).filter(([key, value]) => { + return value === address; + }); + + return entries.map(([key, _value]) => key); + } + + findAlias(name: string): string | null { + const alias = Object.entries(this.aliases).find(([alias, addr]) => alias.toLowerCase() === name.toLowerCase()); + + if (alias) { + return alias[1]; + } else { + return null; + } + } +} diff --git a/scenario/src/Utils.ts b/scenario/src/Utils.ts new file mode 100644 index 000000000..fa8c62051 --- /dev/null +++ b/scenario/src/Utils.ts @@ -0,0 +1,62 @@ +import {Event} from './Event'; +import {World} from './World'; + +// Wraps the element in an array, if it was not already an array +// If array is null or undefined, return the empty array +export function mustArray(arg: T[] | T): T[] { + if (Array.isArray(arg)) { + return arg; + } else { + if (arg === null || arg === undefined) { + return []; + } else { + return [arg]; + } + } +} + +// Asserts that the array must be given length and if so returns it, otherwise +// it will raise an error +export function mustLen(arg: any[] | any, len: number, maxLen?: number): any[] { + if (!Array.isArray(arg)) { + throw `Expected array of length ${len}, got ${arg}`; + } else if (maxLen === undefined && arg.length !== len) { + throw `Expected array of length ${len}, got length ${arg.length} (${arg})`; + } else if (maxLen !== undefined && (arg.length < len || arg.length > maxLen)) { + throw `Expected array of length ${len}-${maxLen}, got length ${arg.length} (${arg})`; + } else { + return arg; + } +} + +export function mustString(arg: Event): string { + if (typeof(arg) === "string") { + return arg; + } + + throw new Error(`Expected string argument, got ${arg.toString()}`); +} + +// Web3 doesn't have a function ABI parser.. not sure why.. but we build a simple encoder +// that accepts "fun(uint256,uint256)" and params and returns the encoded value. +export function encodeABI(world: World, fnABI: string, fnParams: string[]): string { + const regex = /(\w+)\(([\w,]+)\)/; + const res = regex.exec(fnABI); + if (!res) { + throw new Error(`Expected ABI signature, got: ${fnABI}`); + } + const [_, fnName, fnInputs] = <[string, string, string]>res; + const jsonInterface = { + name: fnName, + inputs: fnInputs.split(',').map((i) => ({name: '', type: i})) + }; + return world.web3.eth.abi.encodeFunctionCall(jsonInterface, fnParams); +} + +export function sleep(timeout: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, timeout); + }); +} diff --git a/scenario/src/Value.ts b/scenario/src/Value.ts new file mode 100644 index 000000000..be87535c2 --- /dev/null +++ b/scenario/src/Value.ts @@ -0,0 +1,386 @@ +import {World} from './World'; +import {Event} from './Event'; +import BigNumber from 'bignumber.js'; +import {toEncodableNum} from './Encoding'; +import {formatEvent} from './Formatter'; + +BigNumber.config({ ROUNDING_MODE: 3 }); +const mantissaOne = new BigNumber('1.0e18'); + +export enum Order { + EQUAL, + LESS_THAN, + GREATER_THAN +} + +export interface Value { + compareTo(world: World, given: Value): boolean + compareOrder(world: World, given: Value): Order + toString(): string + truthy(): boolean +} + +function compareInt(a: number, b: number): Order { + if (a === b) { + return Order.EQUAL; + } else if (a > b) { + return Order.GREATER_THAN; + } else { + return Order.LESS_THAN; + } +} + +export class EventV implements Value { + val: Event + + constructor(val) { + this.val = val; + } + + compareTo(world: World, given: Value): boolean { + if (given instanceof EventV) { + return JSON.stringify(this.val) === JSON.stringify(given.val); + } else { + throw new Error(`Cannot compare ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + } + + compareOrder(world: World, given: Value): Order { + throw new Error(`Cannot compare order of ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + + toString() { + return `EventV`; + } + + truthy() { + // This check applies to strings or arrays :) + return this.val.length > 0; + } +} + +export class AnythingV implements Value { + compareTo(world: World, given: Value): boolean { + // Everything is awesome. + return true; + } + + compareOrder(world: World, given: Value): Order { + throw new Error(`Cannot compare order of ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + + toString() { + return `AnythingV<>`; + } + + truthy() { + return true; + } +} + +export class NothingV implements Value { + val: null + + constructor() { + this.val = null; + } + + compareTo(world: World, given: Value): boolean { + // Everything is not awesome. + return false; + } + + compareOrder(world: World, given: Value): Order { + throw new Error(`Cannot compare order of ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + + encode() { + return null; + } + + toString() { + return `NothingV<>`; + } + + truthy() { + return false; + } +} + +export class BoolV implements Value { + val: boolean + + constructor(val) { + this.val = val; + } + + compareTo(world: World, given: Value): boolean { + if (given instanceof BoolV) { + return this.val === given.val; + } else if (given instanceof NumberV) { + return this.compareTo(world, given.toBoolV()); + } else { + throw new Error(`Cannot compare ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + } + + compareOrder(world: World, given: Value): Order { + throw new Error(`Cannot compare order of ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + + toString() { + return `BoolV`; + } + + truthy() { + return this.val; + } +} + +export class StringV implements Value { + val: string + + constructor(val) { + this.val = val; + } + + compareTo(world: World, given: Value): boolean { + if (given instanceof StringV) { + return this.val === given.val; + } else if (given instanceof AddressV) { + return this.val === given.val; + } else { + throw new Error(`Cannot compare ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + } + + compareOrder(world: World, given: Value): Order { + throw new Error(`Cannot compare order of ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + + toString() { + return `StringV`; + } + + truthy() { + return this.val.length > 0; + } +} + +export class MapV implements Value { + val: object + + constructor(val) { + this.val = val; + } + + compareTo(world: World, given: Value): boolean { + if (given instanceof MapV) { + return JSON.stringify(this.val) === JSON.stringify(given.val); + } else { + throw new Error(`Cannot compare ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + } + + compareOrder(world: World, given: Value): Order { + throw new Error(`Cannot compare order of ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + + toString() { + return `MapV`; + } + + truthy() { + return Object.keys(this.val).length > 0; + } +} + +export class AddressV implements Value { + val: string + + constructor(val) { + this.val = val; + } + + compareTo(world: World, given: Value): boolean { + if (given instanceof AddressV) { + return this.val === given.val; + } else if (given instanceof StringV) { + return this.val === given.val; + } else { + throw new Error(`Cannot compare ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + } + + compareOrder(world: World, given: Value): Order { + throw new Error(`Cannot compare order of ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + + toString() { + return `AddressV`; + } + + truthy() { + return this.val !== "0x0000000000000000000000000000000000000000"; + } +} + +export class NumberV implements Value { + val : number | string + + constructor(val: number | string, denom?: number | undefined) { + if (denom) { + this.val = Number(val) / denom; + } else { + this.val = val; + } + } + + toNumber(): number { + return Number(this.val); + } + + encode() { + return toEncodableNum(this.val); + } + + compareTo(world: World, given: Value): boolean { + if (given instanceof NumberV) { + const thisBig = new BigNumber(this.val).toFixed(); + const givenBig = new BigNumber(given.val).toFixed(); + + return thisBig === givenBig; + } else if (given instanceof PreciseV) { + return this.compareTo(world, given.toNumberV()); + } else { + throw new Error(`Cannot compare ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + } + + compareOrder(world: World, given: Value): Order { + if (given instanceof NumberV) { + const thisBig = new BigNumber(this.val).toNumber(); + const givenBig = new BigNumber(given.val).toNumber(); + + return compareInt(thisBig, givenBig); + } else if (given instanceof PreciseV) { + return this.compareOrder(world, given.toNumberV()); + } else { + throw new Error(`Cannot compare ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + } + + toBoolV(): BoolV { + if (this.val === 0) { + return new BoolV(true) + } else if (this.val === 1) { + return new BoolV(false); + } + + throw new Error(`Cannot convert number ${this.val} into bool`) + } + + asExp(denom=undefined): string { + return new BigNumber(this.val).toExponential(); + } + + show(): string { + return new BigNumber(this.val).toExponential(); + } + + toString() { + return `NumberV`; + } + + truthy() { + return this.val != 0; + } + + add(b: NumberV): NumberV { + return new NumberV(new BigNumber(this.val).plus(new BigNumber(b.val)).toFixed()); + } + + sub(b: NumberV): NumberV { + return new NumberV(new BigNumber(this.val).minus(new BigNumber(b.val)).toFixed()); + } +} + +export class ExpNumberV extends NumberV { + show() { + return new BigNumber(this.val).dividedBy(mantissaOne).toNumber().toString(); + } +} + +export class PercentV extends NumberV { + show() { + return new BigNumber(this.val).dividedBy(mantissaOne).multipliedBy(new BigNumber(100)).toNumber().toString() + '%'; + } +} + +export class PreciseV implements Value { + val: number + precision: number + + constructor(val, precision) { + this.val = val; + this.precision = precision; + } + + compareTo(world: World, given: Value): boolean { + if (given instanceof NumberV) { + const thisBig = new BigNumber(this.val.toString()).toPrecision(this.precision); + const givenBig = new BigNumber(given.val.toString()).toPrecision(this.precision); + + return thisBig === givenBig; + } else if (given instanceof PreciseV) { + // TODO: Is this okay? + return this.compareTo(world, given.toNumberV()); + } else { + throw new Error(`Cannot compare ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + } + + compareOrder(world: World, given: Value): Order { + throw new Error(`Cannot compare order of ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + + toNumberV(): NumberV { + return new NumberV(this.val); + } + + toString() { + return `PreciseV`; + } + + truthy() { + return this.val != 0; + } +} + +export class ListV implements Value { + val: Value[] + + constructor(els) { + this.val = els; + } + + compareTo(world: World, given: Value): boolean { + if (given instanceof ListV) { + return this.val.every((el, i) => el.compareTo(world, given.val[i])); + } else { + throw new Error(`Cannot compare ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + } + + compareOrder(world: World, given: Value): Order { + throw new Error(`Cannot compare order of ${typeof this} to ${typeof given} (${this.toString()}, ${given.toString()})`); + } + + toString() { + return `ListV el.toString()).join(',')}>`; + } + + truthy() { + return this.val.length > 0; + } +} diff --git a/scenario/src/Value/CTokenValue.ts b/scenario/src/Value/CTokenValue.ts new file mode 100644 index 000000000..19361f15f --- /dev/null +++ b/scenario/src/Value/CTokenValue.ts @@ -0,0 +1,293 @@ +import {Event} from '../Event'; +import {World} from '../World'; +import {CToken} from '../Contract/CToken'; +import {Erc20} from '../Contract/Erc20'; +import {InterestRateModel} from '../Contract/InterestRateModel'; +import { + getAddressV, + getCoreValue, + mapValue +} from '../CoreValue'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import { + AddressV, + NumberV, + Value, + StringV +} from '../Value'; +import {getWorldContractByAddress, getCTokenAddress} from '../ContractLookup'; + +export async function getCTokenV(world: World, event: Event): Promise { + const address = await mapValue( + world, + event, + (str) => new AddressV(getCTokenAddress(world, str)), + getCoreValue, + AddressV + ); + + return getWorldContractByAddress(world, address.val); +} + +async function cTokenAddress(world: World, cToken: CToken): Promise { + return new AddressV(cToken._address); +} + +async function getCTokenAdmin(world: World, cToken: CToken): Promise { + return new AddressV(await cToken.methods.admin().call()); +} + +async function getCTokenPendingAdmin(world: World, cToken: CToken): Promise { + return new AddressV(await cToken.methods.pendingAdmin().call()); +} + +async function balanceOfUnderlying(world: World, cToken: CToken, user: string): Promise { + return new NumberV(await cToken.methods.balanceOfUnderlying(user).call()); +} + +async function getBorrowBalance(world: World, cToken: CToken, user): Promise { + return new NumberV(await cToken.methods.borrowBalanceCurrent(user).call()); +} + +async function getBorrowBalanceStored(world: World, cToken: CToken, user): Promise { + return new NumberV(await cToken.methods.borrowBalanceStored(user).call()); +} + +async function getTotalBorrows(world: World, cToken: CToken): Promise { + return new NumberV(await cToken.methods.totalBorrows().call()); +} + +async function getTotalBorrowsCurrent(world: World, cToken: CToken): Promise { + return new NumberV(await cToken.methods.totalBorrowsCurrent().call()); +} + +async function getReserveFactor(world: World, cToken: CToken): Promise { + return new NumberV(await cToken.methods.reserveFactorMantissa().call(), 1.0e18); +} + +async function getTotalReserves(world: World, cToken: CToken): Promise { + return new NumberV(await cToken.methods.totalReserves().call()); +} + +async function getComptroller(world: World, cToken: CToken): Promise { + return new AddressV(await cToken.methods.comptroller().call()); +} + +async function getExchangeRateStored(world: World, cToken: CToken): Promise { + return new NumberV(await cToken.methods.exchangeRateStored().call()); +} + +async function getExchangeRate(world: World, cToken: CToken): Promise { + return new NumberV(await cToken.methods.exchangeRateCurrent().call(), 1e18); +} + +async function getInterestRate(world: World, cToken: CToken): Promise { + return new NumberV(await cToken.methods.borrowRatePerBlock().call(), 1.0e18 / 2102400); +} + +export function cTokenFetchers() { + return [ + new Fetcher<{cToken: CToken}, AddressV>(` + #### Address + + * "CToken Address" - Returns address of CToken contract + * E.g. "CToken cZRX Address" - Returns cZRX's address + `, + "Address", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => cTokenAddress(world, cToken), + {namePos: 1} + ), + new Fetcher<{cToken: CToken}, AddressV>(` + #### Admin + + * "CToken Admin" - Returns the admin of CToken contract + * E.g. "CToken cZRX Admin" - Returns cZRX's admin + `, + "Admin", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => getCTokenAdmin(world, cToken), + {namePos: 1} + ), + new Fetcher<{cToken: CToken}, AddressV>(` + #### PendingAdmin + + * "CToken PendingAdmin" - Returns the pending admin of CToken contract + * E.g. "CToken cZRX PendingAdmin" - Returns cZRX's pending admin + `, + "PendingAdmin", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => getCTokenPendingAdmin(world, cToken), + {namePos: 1} + ), + new Fetcher<{cToken: CToken}, AddressV>(` + #### Underlying + + * "CToken Underlying" - Returns the underlying asset (if applicable) + * E.g. "CToken cZRX Underlying" + `, + "Underlying", + [ + new Arg("cToken", getCTokenV) + ], + async (world, {cToken}) => new AddressV(await cToken.methods.underlying().call()), + {namePos: 1} + ), + new Fetcher<{cToken: CToken, address: AddressV}, NumberV>(` + #### UnderlyingBalance + + * "CToken UnderlyingBalance " - Returns a user's underlying balance (based on given exchange rate) + * E.g. "CToken cZRX UnderlyingBalance Geoff" + `, + "UnderlyingBalance", + [ + new Arg("cToken", getCTokenV), + new Arg("address", getAddressV) + ], + (world, {cToken, address}) => balanceOfUnderlying(world, cToken, address.val), + {namePos: 1} + ), + new Fetcher<{cToken: CToken, address: AddressV}, NumberV>(` + #### BorrowBalance + + * "CToken BorrowBalance " - Returns a user's borrow balance (including interest) + * E.g. "CToken cZRX BorrowBalance Geoff" + `, + "BorrowBalance", + [ + new Arg("cToken", getCTokenV), + new Arg("address", getAddressV) + ], + (world, {cToken, address}) => getBorrowBalance(world, cToken, address.val), + {namePos: 1} + ), + new Fetcher<{cToken: CToken, address: AddressV}, NumberV>(` + #### BorrowBalanceStored + + * "CToken BorrowBalanceStored " - Returns a user's borrow balance (without specifically re-accruing interest) + * E.g. "CToken cZRX BorrowBalanceStored Geoff" + `, + "BorrowBalanceStored", + [ + new Arg("cToken", getCTokenV), + new Arg("address", getAddressV) + ], + (world, {cToken, address}) => getBorrowBalanceStored(world, cToken, address.val), + {namePos: 1} + ), + new Fetcher<{cToken: CToken}, NumberV>(` + #### TotalBorrows + + * "CToken TotalBorrows" - Returns the cToken's total borrow balance + * E.g. "CToken cZRX TotalBorrows" + `, + "TotalBorrows", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => getTotalBorrows(world, cToken), + {namePos: 1} + ), + new Fetcher<{cToken: CToken}, NumberV>(` + #### TotalBorrowsCurrent + + * "CToken TotalBorrowsCurrent" - Returns the cToken's total borrow balance with interest + * E.g. "CToken cZRX TotalBorrowsCurrent" + `, + "TotalBorrowsCurrent", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => getTotalBorrowsCurrent(world, cToken), + {namePos: 1} + ), + new Fetcher<{cToken: CToken}, NumberV>(` + #### Reserves + + * "CToken Reserves" - Returns the cToken's total reserves + * E.g. "CToken cZRX Reserves" + `, + "Reserves", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => getTotalReserves(world, cToken), + {namePos: 1} + ), + new Fetcher<{cToken: CToken}, NumberV>(` + #### ReserveFactor + + * "CToken ReserveFactor" - Returns reserve factor of CToken contract + * E.g. "CToken cZRX ReserveFactor" - Returns cZRX's reserve factor + `, + "ReserveFactor", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => getReserveFactor(world, cToken), + {namePos: 1} + ), + new Fetcher<{cToken: CToken}, AddressV>(` + #### Comptroller + + * "CToken Comptroller" - Returns the cToken's comptroller + * E.g. "CToken cZRX Comptroller" + `, + "Comptroller", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => getComptroller(world, cToken), + {namePos: 1} + ), + new Fetcher<{cToken: CToken}, NumberV>(` + #### ExchangeRateStored + + * "CToken ExchangeRateStored" - Returns the cToken's exchange rate (based on balances stored) + * E.g. "CToken cZRX ExchangeRateStored" + `, + "ExchangeRateStored", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => getExchangeRateStored(world, cToken), + {namePos: 1} + ), + new Fetcher<{cToken: CToken}, NumberV>(` + #### ExchangeRate + + * "CToken ExchangeRate" - Returns the cToken's current exchange rate + * E.g. "CToken cZRX ExchangeRate" + `, + "ExchangeRate", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => getExchangeRate(world, cToken), + {namePos: 1} + ), + new Fetcher<{cToken: CToken}, NumberV>(` + #### InterestRate + + * "CToken InterestRate" - Returns the cToken's current interest rate + * E.g. "CToken cZRX InterestRate" + `, + "InterestRate", + [ + new Arg("cToken", getCTokenV) + ], + (world, {cToken}) => getInterestRate(world, cToken), + {namePos: 1} + ) + ]; +} + +export async function getCTokenValue(world: World, event: Event): Promise { + return await getFetcherValue("cToken", cTokenFetchers(), world, event); +} diff --git a/scenario/src/Value/ComptrollerImplValue.ts b/scenario/src/Value/ComptrollerImplValue.ts new file mode 100644 index 000000000..a7678b969 --- /dev/null +++ b/scenario/src/Value/ComptrollerImplValue.ts @@ -0,0 +1,35 @@ +import {Event} from '../Event'; +import {World} from '../World'; +import {ComptrollerImpl} from '../Contract/ComptrollerImpl'; +import { + getAddressV +} from '../CoreValue'; +import { + AddressV, + Value +} from '../Value'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {getComptrollerImpl} from '../ContractLookup'; + +export async function getComptrollerImplAddress(world: World, comptrollerImpl: ComptrollerImpl): Promise { + return new AddressV(comptrollerImpl._address); +} + +export function comptrollerImplFetchers() { + return [ + new Fetcher<{comptrollerImpl: ComptrollerImpl}, AddressV>(` + #### Address + + * "ComptrollerImpl Address" - Returns address of comptroller implementation + `, + "Address", + [new Arg("comptrollerImpl", getComptrollerImpl)], + (world, {comptrollerImpl}) => getComptrollerImplAddress(world, comptrollerImpl), + {namePos: 1} + ) + ]; +} + +export async function getComptrollerImplValue(world: World, event: Event): Promise { + return await getFetcherValue("ComptrollerImpl", comptrollerImplFetchers(), world, event); +} diff --git a/scenario/src/Value/ComptrollerValue.ts b/scenario/src/Value/ComptrollerValue.ts new file mode 100644 index 000000000..7b001f527 --- /dev/null +++ b/scenario/src/Value/ComptrollerValue.ts @@ -0,0 +1,313 @@ +import {Event} from '../Event'; +import {World} from '../World'; +import {Comptroller} from '../Contract/Comptroller'; +import {CToken} from '../Contract/CToken'; +import { + getAddressV, + getStringV, + getNumberV +} from '../CoreValue'; +import { + AddressV, + BoolV, + ListV, + NumberV, + StringV, + Value +} from '../Value'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {getComptroller} from '../ContractLookup'; +import {encodedNumber} from '../Encoding'; +import {getCTokenV} from '../Value/CTokenValue'; + +export async function getComptrollerAddress(world: World, comptroller: Comptroller): Promise { + return new AddressV(comptroller._address); +} + +export async function getLiquidity(world: World, comptroller: Comptroller, user: string): Promise { + let {0: error, 1: liquidity, 2: shortfall} = await comptroller.methods.getAccountLiquidity(user).call(); + if (Number(error) != 0) { + throw new Error(`Failed to compute account liquidity: error code = ${error}`); + } + return new NumberV(Number(liquidity) - Number(shortfall)); +} + +export async function getHypotheticalLiquidity(world: World, comptroller: Comptroller, account: string, asset: string, redeemTokens: encodedNumber, borrowAmount: encodedNumber): Promise { + let {0: error, 1: liquidity, 2: shortfall} = await comptroller.methods.getHypotheticalAccountLiquidity(account, asset, redeemTokens, borrowAmount).call(); + if (Number(error) != 0) { + throw new Error(`Failed to compute account hypothetical liquidity: error code = ${error}`); + } + return new NumberV(Number(liquidity) - Number(shortfall)); +} + +async function getPriceOracle(world: World, comptroller: Comptroller): Promise { + return new AddressV(await comptroller.methods.oracle().call()); +} + +async function getCloseFactor(world: World, comptroller: Comptroller): Promise { + return new NumberV(await comptroller.methods.closeFactorMantissa().call(), 1e18); +} + +async function getMaxAssets(world: World, comptroller: Comptroller): Promise { + return new NumberV(await comptroller.methods.maxAssets().call()); +} + +async function getLiquidationIncentive(world: World, comptroller: Comptroller): Promise { + return new NumberV(await comptroller.methods.liquidationIncentiveMantissa().call(), 1e18); +} + +async function getImplementation(world: World, comptroller: Comptroller): Promise { + return new AddressV(await comptroller.methods.comptrollerImplementation().call()); +} + +async function getBlockNumber(world: World, comptroller: Comptroller): Promise { + return new NumberV(await comptroller.methods.blockNumber().call()); +} + +async function getAdmin(world: World, comptroller: Comptroller): Promise { + return new AddressV(await comptroller.methods.admin().call()); +} + +async function getPendingAdmin(world: World, comptroller: Comptroller): Promise { + return new AddressV(await comptroller.methods.pendingAdmin().call()); +} + +async function getCollateralFactor(world: World, comptroller: Comptroller, cToken: CToken): Promise { + let {0: _isListed, 1: collateralFactorMantissa} = await comptroller.methods.markets(cToken._address).call(); + + return new NumberV(collateralFactorMantissa, 1e18); +} + +async function membershipLength(world: World, comptroller: Comptroller, user: string): Promise { + return new NumberV(await comptroller.methods.membershipLength(user).call()); +} + +async function checkMembership(world: World, comptroller: Comptroller, user: string, cToken: CToken): Promise { + return new BoolV(await comptroller.methods.checkMembership(user, cToken._address).call()); +} + +async function getAssetsIn(world: World, comptroller: Comptroller, user: string): Promise { + let assetsList = await comptroller.methods.getAssetsIn(user).call(); + + return new ListV(assetsList.map((a) => new AddressV(a))); +} + +async function checkListed(world: World, comptroller: Comptroller, cToken: CToken): Promise { + let {0: isListed, 1: _collateralFactorMantissa} = await comptroller.methods.markets(cToken._address).call(); + + return new BoolV(isListed); +} + +export function comptrollerFetchers() { + return [ + new Fetcher<{comptroller: Comptroller}, AddressV>(` + #### Address + + * "Comptroller Address" - Returns address of comptroller + `, + "Address", + [new Arg("comptroller", getComptroller, {implicit: true})], + (world, {comptroller}) => getComptrollerAddress(world, comptroller) + ), + new Fetcher<{comptroller: Comptroller, account: AddressV}, NumberV>(` + #### Liquidity + + * "Comptroller Liquidity " - Returns a given user's trued up liquidity + * E.g. "Comptroller Liquidity Geoff" + `, + "Liquidity", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("account", getAddressV) + ], + (world, {comptroller, account}) => getLiquidity(world, comptroller, account.val) + ), + new Fetcher<{comptroller: Comptroller, account: AddressV, action: StringV, amount: NumberV, cToken: CToken}, NumberV>(` + #### Hypothetical + + * "Comptroller Hypothetical " - Returns a given user's trued up liquidity given a hypothetical change in asset with redeeming a certain number of tokens and/or borrowing a given amount. + * E.g. "Comptroller Hypothetical Geoff Redeems 6.0 cZRX" + * E.g. "Comptroller Hypothetical Geoff Borrows 5.0 cZRX" + `, + "Hypothetical", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("account", getAddressV), + new Arg("action", getStringV), + new Arg("amount", getNumberV), + new Arg("cToken", getCTokenV) + ], + async (world, {comptroller, account, action, cToken, amount}) => { + let redeemTokens: NumberV; + let borrowAmount: NumberV; + + switch (action.val.toLowerCase()) { + case "borrows": + redeemTokens = new NumberV(0); + borrowAmount = amount; + break; + case "redeems": + redeemTokens = amount; + borrowAmount = new NumberV(0); + break; + default: + throw new Error(`Unknown hypothetical: ${action.val}`); + } + + return await getHypotheticalLiquidity(world, comptroller, account.val, cToken._address, redeemTokens.encode(), borrowAmount.encode()); + } + ), + new Fetcher<{comptroller: Comptroller}, AddressV>(` + #### Admin + + * "Comptroller Admin" - Returns the Comptrollers's admin + * E.g. "Comptroller Admin" + `, + "Admin", + [new Arg("comptroller", getComptroller, {implicit: true})], + (world, {comptroller}) => getAdmin(world, comptroller) + ), + new Fetcher<{comptroller: Comptroller}, AddressV>(` + #### PendingAdmin + + * "Comptroller PendingAdmin" - Returns the pending admin of the Comptroller + * E.g. "Comptroller PendingAdmin" - Returns Comptroller's pending admin + `, + "PendingAdmin", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + ], + (world, {comptroller}) => getPendingAdmin(world, comptroller) + ), + new Fetcher<{comptroller: Comptroller}, AddressV>(` + #### PriceOracle + + * "Comptroller PriceOracle" - Returns the Comptrollers's price oracle + * E.g. "Comptroller PriceOracle" + `, + "PriceOracle", + [new Arg("comptroller", getComptroller, {implicit: true})], + (world, {comptroller}) => getPriceOracle(world, comptroller) + ), + new Fetcher<{comptroller: Comptroller}, NumberV>(` + #### CloseFactor + + * "Comptroller CloseFactor" - Returns the Comptrollers's price oracle + * E.g. "Comptroller CloseFactor" + `, + "CloseFactor", + [new Arg("comptroller", getComptroller, {implicit: true})], + (world, {comptroller}) => getCloseFactor(world, comptroller) + ), + new Fetcher<{comptroller: Comptroller}, NumberV>(` + #### MaxAssets + + * "Comptroller MaxAssets" - Returns the Comptrollers's price oracle + * E.g. "Comptroller MaxAssets" + `, + "MaxAssets", + [new Arg("comptroller", getComptroller, {implicit: true})], + (world, {comptroller}) => getMaxAssets(world, comptroller) + ), + new Fetcher<{comptroller: Comptroller}, NumberV>(` + #### LiquidationIncentive + + * "Comptroller LiquidationIncentive" - Returns the Comptrollers's liquidation incentive + * E.g. "Comptroller LiquidationIncentive" + `, + "LiquidationIncentive", + [new Arg("comptroller", getComptroller, {implicit: true})], + (world, {comptroller}) => getLiquidationIncentive(world, comptroller) + ), + new Fetcher<{comptroller: Comptroller}, AddressV>(` + #### Implementation + + * "Comptroller Implementation" - Returns the Comptrollers's implementation + * E.g. "Comptroller Implementation" + `, + "Implementation", + [new Arg("comptroller", getComptroller, {implicit: true})], + (world, {comptroller}) => getImplementation(world, comptroller) + ), + new Fetcher<{comptroller: Comptroller}, NumberV>(` + #### BlockNumber + + * "Comptroller BlockNumber" - Returns the Comptrollers's mocked block number (for scenario runner) + * E.g. "Comptroller BlockNumber" + `, + "BlockNumber", + [new Arg("comptroller", getComptroller, {implicit: true})], + (world, {comptroller}) => getBlockNumber(world, comptroller) + ), + new Fetcher<{comptroller: Comptroller, cToken: CToken}, NumberV>(` + #### CollateralFactor + + * "Comptroller CollateralFactor " - Returns the collateralFactor associated with a given asset + * E.g. "Comptroller CollateralFactor cZRX" + `, + "CollateralFactor", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("cToken", getCTokenV) + ], + (world, {comptroller, cToken}) => getCollateralFactor(world, comptroller, cToken) + ), + new Fetcher<{comptroller: Comptroller, account: AddressV}, NumberV>(` + #### MembershipLength + + * "Comptroller MembershipLength " - Returns a given user's length of membership + * E.g. "Comptroller MembershipLength Geoff" + `, + "MembershipLength", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("account", getAddressV) + ], + (world, {comptroller, account}) => membershipLength(world, comptroller, account.val) + ), + new Fetcher<{comptroller: Comptroller, account: AddressV, cToken: CToken}, BoolV>(` + #### CheckMembership + + * "Comptroller CheckMembership " - Returns one if user is in asset, zero otherwise. + * E.g. "Comptroller CheckMembership Geoff cZRX" + `, + "CheckMembership", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("account", getAddressV), + new Arg("cToken", getCTokenV) + ], + (world, {comptroller, account, cToken}) => checkMembership(world, comptroller, account.val, cToken) + ), + new Fetcher<{comptroller: Comptroller, account: AddressV}, ListV>(` + #### AssetsIn + + * "Comptroller AssetsIn " - Returns the assets a user is in + * E.g. "Comptroller AssetsIn Geoff" + `, + "AssetsIn", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("account", getAddressV) + ], + (world, {comptroller, account}) => getAssetsIn(world, comptroller, account.val) + ), + new Fetcher<{comptroller: Comptroller, cToken: CToken}, BoolV>(` + #### CheckListed + + * "Comptroller CheckListed " - Returns true if market is listed, false otherwise. + * E.g. "Comptroller CheckListed cZRX" + `, + "CheckListed", + [ + new Arg("comptroller", getComptroller, {implicit: true}), + new Arg("cToken", getCTokenV) + ], + (world, {comptroller, cToken}) => checkListed(world, comptroller, cToken) + ) + ]; +} + +export async function getComptrollerValue(world: World, event: Event): Promise { + return await getFetcherValue("Comptroller", comptrollerFetchers(), world, event); +} diff --git a/scenario/src/Value/Erc20Value.ts b/scenario/src/Value/Erc20Value.ts new file mode 100644 index 000000000..8f31716b0 --- /dev/null +++ b/scenario/src/Value/Erc20Value.ts @@ -0,0 +1,160 @@ +import {Event} from '../Event'; +import {World} from '../World'; +import {Erc20} from '../Contract/Erc20'; +import {getErc20Address, getWorldContractByAddress} from '../ContractLookup'; +import { + getAddressV, + getCoreValue, + mapValue, +} from '../CoreValue'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import { + AddressV, + NumberV, + Value, + StringV +} from '../Value'; + +export async function getErc20Name(world: World, erc20: Erc20): Promise { + return new StringV(await erc20.methods.name().call()); +} + +export async function getErc20Symbol(world: World, erc20: Erc20): Promise { + return new StringV(await erc20.methods.symbol().call()); +} + +export async function getErc20Decimals(world: World, erc20: Erc20): Promise { + return new NumberV(await erc20.methods.decimals().call()); +} + +async function getTotalSupply(world: World, erc20: Erc20): Promise { + return new NumberV(await erc20.methods.totalSupply().call()); +} + +async function getTokenBalance(world: World, erc20: Erc20, address: string): Promise { + return new NumberV(await erc20.methods.balanceOf(address).call()); +} + +async function getAllowance(world: World, erc20: Erc20, owner: string, spender: string): Promise { + return new NumberV(await erc20.methods.allowance(owner, spender).call()); +} + +export async function getErc20V(world: World, event: Event): Promise { + const address = await mapValue( + world, + event, + (str) => new AddressV(getErc20Address(world, str)), + getCoreValue, + AddressV + ); + + return getWorldContractByAddress(world, address.val); +} + +export function erc20Fetchers() { + return [ + new Fetcher<{erc20: Erc20}, AddressV>(` + #### Address + + * "Erc20 Address" - Returns address of ERC-20 contract + * E.g. "Erc20 ZRX Address" - Returns ZRX's address + `, + "Address", + [ + new Arg("erc20", getErc20V) + ], + async (world, {erc20}) => new AddressV(erc20._address), + {namePos: 1} + ), + new Fetcher<{erc20: Erc20}, StringV>(` + #### Name + + * "Erc20 Name" - Returns name of ERC-20 contract + * E.g. "Erc20 ZRX Name" - Returns ZRX's name + `, + "Name", + [ + new Arg("erc20", getErc20V) + ], + (world, {erc20}) => getErc20Name(world, erc20), + {namePos: 1} + ), + new Fetcher<{erc20: Erc20}, StringV>(` + #### Symbol + + * "Erc20 Symbol" - Returns symbol of ERC-20 contract + * E.g. "Erc20 ZRX Symbol" - Returns ZRX's symbol + `, + "Symbol", + [ + new Arg("erc20", getErc20V) + ], + (world, {erc20}) => getErc20Symbol(world, erc20), + {namePos: 1} + ), + new Fetcher<{erc20: Erc20}, NumberV>(` + #### Decimals + + * "Erc20 Decimals" - Returns number of decimals in ERC-20 contract + * E.g. "Erc20 ZRX Decimals" - Returns ZRX's decimals + `, + "Decimals", + [ + new Arg("erc20", getErc20V) + ], + (world, {erc20}) => getErc20Decimals(world, erc20), + {namePos: 1} + ), + new Fetcher<{erc20: Erc20}, NumberV>(` + #### TotalSupply + + * "Erc20 TotalSupply" - Returns the ERC-20 token's total supply + * E.g. "Erc20 ZRX TotalSupply" + * E.g. "Erc20 cZRX TotalSupply" + `, + "TotalSupply", + [ + new Arg("erc20", getErc20V) + ], + (world, {erc20}) => getTotalSupply(world, erc20), + {namePos: 1} + ), + new Fetcher<{erc20: Erc20, address: AddressV}, NumberV>(` + #### TokenBalance + + * "Erc20 TokenBalance
" - Returns the ERC-20 token balance of a given address + * E.g. "Erc20 ZRX TokenBalance Geoff" - Returns a user's ZRX balance + * E.g. "Erc20 cZRX TokenBalance Geoff" - Returns a user's cZRX balance + * E.g. "Erc20 ZRX TokenBalance cZRX" - Returns cZRX's ZRX balance + `, + "TokenBalance", + [ + new Arg("erc20", getErc20V), + new Arg("address", getAddressV) + ], + (world, {erc20, address}) => getTokenBalance(world, erc20, address.val), + {namePos: 1} + ), + new Fetcher<{erc20: Erc20, owner: AddressV, spender: AddressV}, NumberV>(` + #### Allowance + + * "Erc20 Allowance owner:
spender:
" - Returns the ERC-20 allowance from owner to spender + * E.g. "Erc20 ZRX Allowance Geoff Torrey" - Returns the ZRX allowance of Geoff to Torrey + * E.g. "Erc20 cZRX Allowance Geoff Coburn" - Returns the cZRX allowance of Geoff to Coburn + * E.g. "Erc20 ZRX Allowance Geoff cZRX" - Returns the ZRX allowance of Geoff to the cZRX cToken + `, + "Allowance", + [ + new Arg("erc20", getErc20V), + new Arg("owner", getAddressV), + new Arg("spender", getAddressV) + ], + (world, {erc20, owner, spender}) => getAllowance(world, erc20, owner.val, spender.val), + {namePos: 1} + ) + ]; +} + +export async function getErc20Value(world: World, event: Event): Promise { + return await getFetcherValue("Erc20", erc20Fetchers(), world, event); +} diff --git a/scenario/src/Value/InterestRateModelValue.ts b/scenario/src/Value/InterestRateModelValue.ts new file mode 100644 index 000000000..bbe75e197 --- /dev/null +++ b/scenario/src/Value/InterestRateModelValue.ts @@ -0,0 +1,38 @@ +import {Event} from '../Event'; +import {World} from '../World'; +import {InterestRateModel} from '../Contract/InterestRateModel'; +import { + getAddressV +} from '../CoreValue'; +import { + AddressV, + NumberV, + Value} from '../Value'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {getInterestRateModel} from '../ContractLookup'; + +export async function getInterestRateModelAddress(world: World, interestRateModel: InterestRateModel): Promise { + return new AddressV(interestRateModel._address); +} + +export function interestRateModelFetchers() { + return [ + new Fetcher<{interestRateModel: InterestRateModel}, AddressV>(` + #### Address + + * " Address" - Gets the address of the global price oracle + * E.g. "InterestRateModel MyInterestRateModel Address" + `, + "Address", + [ + new Arg("interestRateModel", getInterestRateModel) + ], + (world, {interestRateModel}) => getInterestRateModelAddress(world, interestRateModel), + {namePos: 1} + ) + ]; +} + +export async function getInterestRateModelValue(world: World, event: Event): Promise { + return await getFetcherValue("InterestRateModel", interestRateModelFetchers(), world, event); +} diff --git a/scenario/src/Value/MaximillionValue.ts b/scenario/src/Value/MaximillionValue.ts new file mode 100644 index 000000000..eaf701e52 --- /dev/null +++ b/scenario/src/Value/MaximillionValue.ts @@ -0,0 +1,34 @@ +import {Event} from '../Event'; +import {World} from '../World'; +import {Maximillion} from '../Contract/Maximillion'; +import { + getAddressV +} from '../CoreValue'; +import { + AddressV, + Value +} from '../Value'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {getMaximillion} from '../ContractLookup'; + +export async function getMaximillionAddress(world: World, maximillion: Maximillion): Promise { + return new AddressV(maximillion._address); +} + +export function maximillionFetchers() { + return [ + new Fetcher<{maximillion: Maximillion}, AddressV>(` + #### Address + + * "Maximillion Address" - Returns address of maximillion + `, + "Address", + [new Arg("maximillion", getMaximillion, {implicit: true})], + (world, {maximillion}) => getMaximillionAddress(world, maximillion) + ) + ]; +} + +export async function getMaximillionValue(world: World, event: Event): Promise { + return await getFetcherValue("Maximillion", maximillionFetchers(), world, event); +} diff --git a/scenario/src/Value/PriceOracleProxyValue.ts b/scenario/src/Value/PriceOracleProxyValue.ts new file mode 100644 index 000000000..2eabec18e --- /dev/null +++ b/scenario/src/Value/PriceOracleProxyValue.ts @@ -0,0 +1,52 @@ +import {Event} from '../Event'; +import {World} from '../World'; +import {PriceOracleProxy} from '../Contract/PriceOracleProxy'; +import { + getAddressV +} from '../CoreValue'; +import { + AddressV, + NumberV, + Value} from '../Value'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {getPriceOracleProxy} from '../ContractLookup'; + +export async function getPriceOracleProxyAddress(world: World, priceOracleProxy: PriceOracleProxy): Promise { + return new AddressV(priceOracleProxy._address); +} + +async function getPrice(world: World, priceOracleProxy: PriceOracleProxy, asset: string): Promise { + return new NumberV(await priceOracleProxy.methods.getUnderlyingPrice(asset).call()); +} + +export function priceOracleProxyFetchers() { + return [ + new Fetcher<{priceOracleProxy: PriceOracleProxy}, AddressV>(` + #### Address + + * "Address" - Gets the address of the global price oracle + `, + "Address", + [ + new Arg("priceOracleProxy", getPriceOracleProxy, {implicit: true}) + ], + (world, {priceOracleProxy}) => getPriceOracleProxyAddress(world, priceOracleProxy) + ), + new Fetcher<{priceOracle: PriceOracleProxy, asset: AddressV}, NumberV>(` + #### Price + + * "Price asset:
" - Gets the price of the given asset + `, + "Price", + [ + new Arg("priceOracle", getPriceOracleProxy, {implicit: true}), + new Arg("asset", getAddressV) + ], + (world, {priceOracle, asset}) => getPrice(world, priceOracle, asset.val) + ) + ]; +} + +export async function getPriceOracleProxyValue(world: World, event: Event): Promise { + return await getFetcherValue("PriceOracle", priceOracleProxyFetchers(), world, event); +} diff --git a/scenario/src/Value/PriceOracleValue.ts b/scenario/src/Value/PriceOracleValue.ts new file mode 100644 index 000000000..f954bec9d --- /dev/null +++ b/scenario/src/Value/PriceOracleValue.ts @@ -0,0 +1,52 @@ +import {Event} from '../Event'; +import {World} from '../World'; +import {PriceOracle} from '../Contract/PriceOracle'; +import { + getAddressV +} from '../CoreValue'; +import { + AddressV, + NumberV, + Value} from '../Value'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {getPriceOracle} from '../ContractLookup'; + +async function getPrice(world: World, priceOracle: PriceOracle, asset: string): Promise { + return new NumberV(await priceOracle.methods.assetPrices(asset).call()); +} + +export async function getPriceOracleAddress(world: World, priceOracle: PriceOracle): Promise { + return new AddressV(priceOracle._address); +} + +export function priceOracleFetchers() { + return [ + new Fetcher<{priceOracle: PriceOracle}, AddressV>(` + #### Address + + * "Address" - Gets the address of the global price oracle + `, + "Address", + [ + new Arg("priceOracle", getPriceOracle, {implicit: true}) + ], + (world, {priceOracle}) => getPriceOracleAddress(world, priceOracle) + ), + new Fetcher<{priceOracle: PriceOracle, asset: AddressV}, NumberV>(` + #### Price + + * "Price asset:
" - Gets the price of the given asset + `, + "Price", + [ + new Arg("priceOracle", getPriceOracle, {implicit: true}), + new Arg("asset", getAddressV,) + ], + (world, {priceOracle, asset}) => getPrice(world, priceOracle, asset.val) + ) + ]; +} + +export async function getPriceOracleValue(world: World, event: Event): Promise { + return await getFetcherValue("PriceOracle", priceOracleFetchers(), world, event); +} diff --git a/scenario/src/Value/UnitrollerValue.ts b/scenario/src/Value/UnitrollerValue.ts new file mode 100644 index 000000000..0dcea38bc --- /dev/null +++ b/scenario/src/Value/UnitrollerValue.ts @@ -0,0 +1,34 @@ +import {Event} from '../Event'; +import {World} from '../World'; +import {Unitroller} from '../Contract/Unitroller'; +import { + getAddressV +} from '../CoreValue'; +import { + AddressV, + Value +} from '../Value'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import {getUnitroller} from '../ContractLookup'; + +export async function getUnitrollerAddress(world: World, unitroller: Unitroller): Promise { + return new AddressV(unitroller._address); +} + +export function unitrollerFetchers() { + return [ + new Fetcher<{unitroller: Unitroller}, AddressV>(` + #### Address + + * "Unitroller Address" - Returns address of unitroller + `, + "Address", + [new Arg("unitroller", getUnitroller, {implicit: true})], + (world, {unitroller}) => getUnitrollerAddress(world, unitroller) + ) + ]; +} + +export async function getUnitrollerValue(world: World, event: Event): Promise { + return await getFetcherValue("Unitroller", unitrollerFetchers(), world, event); +} diff --git a/scenario/src/Value/UserValue.ts b/scenario/src/Value/UserValue.ts new file mode 100644 index 000000000..df183ccf1 --- /dev/null +++ b/scenario/src/Value/UserValue.ts @@ -0,0 +1,36 @@ +import {Event} from '../Event'; +import {World} from '../World'; +import { + getAddressV +} from '../CoreValue'; +import {Arg, Fetcher, getFetcherValue} from '../Command'; +import { + AddressV, + Value +} from '../Value'; + +async function getUserAddress(world: World, user: string): Promise { + return new AddressV(user); +} + +export function userFetchers() { + return [ + new Fetcher<{account: AddressV}, AddressV>(` + #### Address + + * "User Address" - Returns address of user + * E.g. "User Geoff Address" - Returns Geoff's address + `, + "Address", + [ + new Arg("account", getAddressV) + ], + async (world, {account}) => account, + {namePos: 1} + ) + ]; +} + +export async function getUserValue(world: World, event: Event): Promise { + return await getFetcherValue("User", userFetchers(), world, event); +} diff --git a/scenario/src/Verify.ts b/scenario/src/Verify.ts new file mode 100644 index 000000000..03b41c10e --- /dev/null +++ b/scenario/src/Verify.ts @@ -0,0 +1,157 @@ +import {World} from './World'; +import {readFile} from './File'; +import request from 'request'; +import * as path from 'path'; +import truffleFlattener from 'truffle-flattener'; +import {getNetworkContracts} from './Contract'; + +interface DevDoc { + author: string + methods: object + title: string +} + +interface UserDoc { + methods: object + notice: string +} + +function getUrl(network: string): string { + let host = { + kovan: 'api-kovan.etherscan.io', + rinkeby: 'api-rinkeby.etherscan.io', + ropsten: 'api-ropsten.etherscan.io', + goerli: 'api-goerli.etherscan.io', + mainnet: 'api.etherscan.io' + }[network]; + + if (!host) { + throw new Error(`Unknown etherscan API host for network ${network}`); + } + + return `https://${host}/api`; +} + +function getConstructorABI(world: World, contractName: string): string { + let constructorAbi = world.getIn(['contractData', 'Constructors', contractName]); + + if (!constructorAbi) { + throw new Error(`Unknown Constructor ABI for ${contractName} on ${world.network}. Try deploying again?`); + } + + return constructorAbi; +} + +function post(url, data): Promise { + return new Promise((resolve, reject) => { + request.post(url, {form: data}, (err, httpResponse, body) => { + if (err) { + reject(err); + } else { + resolve(JSON.parse(body)); + } + }); + }); +} + +function get(url, data): Promise { + return new Promise((resolve, reject) => { + request.get(url, {form: data}, (err, httpResponse, body) => { + if (err) { + reject(err); + } else { + resolve(JSON.parse(body)); + } + }); + }); +} + +interface Result { + status: string + message: string + result: string +} + +async function sleep(timeout): Promise { + return new Promise((resolve, _reject) => { + setTimeout(() => resolve(), timeout); + }) +} + +async function checkStatus(world: World, url: string, token: string): Promise { + world.printer.printLine(`Checking status of ${token}...`); + + // Potential results: + // { status: '0', message: 'NOTOK', result: 'Fail - Unable to verify' } + // { status: '0', message: 'NOTOK', result: 'Pending in queue' } + // { status: '1', message: 'OK', result: 'Pass - Verified' } + + let result: Result = await get(url, { + guid: token, + module: "contract", + action: "checkverifystatus" + }); + + if (world.verbose) { + console.log(result); + } + + if (result.result === "Pending in queue") { + await sleep(5000); + return await checkStatus(world, url, token); + } + + if (result.result.startsWith('Fail')) { + throw new Error(`Etherscan failed to verify contract: ${result.message} "${result.result}"`) + } + + if (Number(result.status) !== 1) { + throw new Error(`Etherscan Error: ${result.message} "${result.result}"`) + } + + world.printer.printLine(`Verification result ${result.result}...`); +} + +export async function verify(world: World, apiKey: string, contractName: string, buildInfoName: string, address: string): Promise { + let contractAddress: string = address; + let {networkContracts, version} = await getNetworkContracts(world); + let networkContract = networkContracts[buildInfoName]; + if (!networkContract) { + throw new Error(`Cannot find contract ${buildInfoName}, found: ${Object.keys(networkContracts)}`) + } + let sourceCode: string = await truffleFlattener([networkContract.path]); + let compilerVersion: string = version.replace(/(\.Emscripten)|(\.clang)|(\.Darwin)|(\.appleclang)/gi, ''); + let constructorAbi = getConstructorABI(world, contractName); + let url = getUrl(world.network); + + const verifyData: object = { + apikey: apiKey, + module: 'contract', + action: 'verifysourcecode', + contractaddress: contractAddress, + sourceCode: sourceCode, + contractname: buildInfoName, + compilerversion: `v${compilerVersion}`, + optimizationUsed: '1', + runs: '200', + constructorArguements: constructorAbi.slice(2) + }; + + world.printer.printLine(`Verifying ${contractName} at ${address} with compiler version ${compilerVersion}...`); + + // Potential results + // {"status":"0","message":"NOTOK","result":"Invalid constructor arguments provided. Please verify that they are in ABI-encoded format"} + // {"status":"1","message":"OK","result":"usjpiyvmxtgwyee59wnycyiet7m3dba4ccdi6acdp8eddlzdde"} + + let result: Result = await post(url, verifyData); + + if (Number(result.status) === 0 || result.message !== "OK") { + if (result.result.includes('Contract source code already verified')) { + world.printer.printLine(`Contract already verified`); + } else { + throw new Error(`Etherscan Error: ${result.message}: ${result.result}`) + } + } else { + return await checkStatus(world, url, result.result); + } +} diff --git a/scenario/src/Web.ts b/scenario/src/Web.ts new file mode 100644 index 000000000..f68e4bbaf --- /dev/null +++ b/scenario/src/Web.ts @@ -0,0 +1,29 @@ +import {parse} from './Parser'; +import {IWeb3, World, initWorld} from './World'; +import {throwAssert} from './Assert'; +import {CallbackPrinter} from './Printer'; +import {runCommand} from './Runner'; +import {loadContractData, parseNetworkFile} from './Networks'; + +export async function webWorld(web3: IWeb3, networksData: string, networksABIData: string, printerCallback: (message: any) => void): Promise { + let printer = new CallbackPrinter(printerCallback); + let accounts = [web3.currentProvider.address]; + let network = 'rinkeby'; // TODO: Get from web3 + + let world = await initWorld(throwAssert, printer, web3, null, network, accounts, null); + + let networks = parseNetworkFile(networksData); + let networksABI = parseNetworkFile(networksABIData); + + [world,] = await loadContractData(world, networks, networksABI); + // world = loadInvokationOpts(world); + // world = loadVerbose(world); + // world = loadDryRun(world); + // world = await loadSettings(world); + + return world; +} + +export async function webParse(world: World, line: string): Promise { + return runCommand(world, line, {}); +} diff --git a/scenario/src/World.ts b/scenario/src/World.ts new file mode 100644 index 000000000..6319c57d2 --- /dev/null +++ b/scenario/src/World.ts @@ -0,0 +1,346 @@ +import {Assert, throwAssert} from './Assert'; +import {Action} from './Action'; +import {Contract} from './Contract'; +import {Record} from 'immutable'; +import {Artifacts} from './Artifact'; +import {Printer} from './Printer'; +import {Invariant} from './Invariant'; +import {SuccessInvariant} from './Invariant/SuccessInvariant'; +import {RemainsInvariant} from './Invariant/RemainsInvariant'; +import {StaticInvariant} from './Invariant/StaticInvariant'; +import {Expectation} from './Expectation'; +import {formatResult} from './ErrorReporter'; +import {Invokation, InvokationOpts} from './Invokation'; +import {Event} from './Event'; +import {formatEvent} from './Formatter'; +import {Map} from 'immutable'; +import {Settings} from './Settings'; +import {Accounts, loadAccounts} from './Accounts'; +import Web3 from 'web3'; + +export interface IWeb3 { + currentProvider: any +} + +const startingBlockNumber = 1000; + +type ContractIndex = { [address:string]: Contract; }; + +export interface WorldProps { + actions: Action[], + event: Event | null, + lastInvokation: Invokation | null + newInvokation: boolean + blockNumber: number + lastContract: Contract | null + invariants: Invariant[] + expectations: Expectation[] + contractIndex: ContractIndex, + contractData: Map, + assert: Assert, + web3: Web3 | null, + artifacts: Artifacts | null + printer: Printer | null + network: string | null, + dryRun: boolean, + verbose: boolean, + settings: Settings, + accounts: Accounts | null, + invokationOpts: InvokationOpts, + trxInvokationOpts: Map, + basePath: string | null +} + +const defaultWorldProps : WorldProps = { + actions: []> [], + event: null, + lastInvokation: null, + newInvokation: false, + blockNumber: 0, + lastContract: null, + invariants: [], + expectations: [], + contractIndex: {}, + contractData: Map({}), + assert: throwAssert, + web3: null, + artifacts: null, + printer: null, + network: null, + dryRun: false, + verbose: false, + settings: Settings.default(null, null), + accounts: null, + invokationOpts: {}, + trxInvokationOpts: Map({}), + basePath: null +}; + +export class World extends Record(defaultWorldProps) { + public readonly actions!: Action[] + public readonly event!: Event | null + public readonly value!: number | null + public readonly lastInvokation!: Invokation | null + public readonly newInvokation!: boolean + public readonly blockNumber!: number + public readonly lastContract!: Contract | null + public readonly invariants!: Invariant[] + public readonly expectations!: Expectation[] + public readonly contractIndex!: ContractIndex + public readonly contractData!: Map + public readonly assert!: Assert + public readonly web3!: Web3 + public readonly artifacts!: Artifacts | null + public readonly printer!: Printer + public readonly network!: string + public readonly dryRun!: boolean + public readonly verbose!: boolean + public readonly settings!: Settings + public readonly accounts!: Accounts + public readonly invokationOpts!: InvokationOpts + public readonly trxInvokationOpts!: Map + public readonly basePath!: string | null + + public constructor(values?: Partial) { + values ? super(values) : super() + } + + getInvokationOpts(baseOpts: InvokationOpts): InvokationOpts { + return { + ...baseOpts, + ...this.invokationOpts, + ...{value: this.value ? this.value.toString() : undefined} + }; + } + + isLocalNetwork(): boolean { + return this.network === "test" || this.network === "development" || this.network === "coverage"; + } + + async updateSettings(fn: (settings: Settings) => Promise): Promise { + // TODO: Should we do an immutable update? + const newSettings = await fn(this.settings); + + // TODO: Should we await or just let it clobber? + await newSettings.save(); + + return this.set('settings', newSettings); + } + + defaultFrom(): string | null { + let settingsFrom = this.settings.findAlias('Me'); + if (settingsFrom) { + return settingsFrom; + } + + let accountsDefault = this.accounts.get('default'); + if (accountsDefault) { + return accountsDefault.address; + } + + return null; + } +} + +export function loadInvokationOpts(world: World): World { + let networkOpts = {}; + const networkOptsStr = process.env[`${world.network}_opts`]; + if (networkOptsStr) { + networkOpts = JSON.parse(networkOptsStr); + } + + return world.set('invokationOpts', networkOpts); +} + +export function loadVerbose(world: World): World { + return world.set('verbose', !!process.env['verbose']); +} + +export function loadDryRun(world: World): World { + return world.set('dryRun', !!process.env['dry_run']); +} + +export async function loadSettings(world: World): Promise { + if (world.basePath) { + return world.set('settings', await Settings.load(world.basePath, world.network)); + } else { + return world; + } +} + +export async function initWorld(assert: Assert, printer: Printer, iweb3: IWeb3, artifacts: Artifacts | null, network: string, accounts: string[], basePath: string | null): Promise { + let web3 = new Web3(iweb3.currentProvider); + + return new World({ + actions: [], + event: null, + lastInvokation: null, + newInvokation: true, + blockNumber: startingBlockNumber, + lastContract: null, + invariants: [new SuccessInvariant()], // Start with invariant success, + expectations: [], + contractIndex: {}, + contractData: Map({}), + assert: assert, + web3: web3, + artifacts: artifacts, + printer: printer, + network: network, + settings: Settings.default(basePath, null), + accounts: loadAccounts(accounts), + trxInvokationOpts: Map({}), + basePath: basePath + }); +} + +export function setEvent(world: World, event: Event): World { + return world.set( + 'event', + event + ); +}; + +export function addAction(world: World, log: string, invokation: Invokation): World { + const action = new Action(log, invokation); + + world = world.update( + 'actions', + (actions) => actions.concat([action]) + ); + + // Print the action via the printer + world.printer.printAction(action); + + return world.merge( + world, + { + lastInvokation: invokation, + newInvokation: true + } + ); +} + +export function addInvariant(world: World, invariant: Invariant): World { + return world.update( + 'invariants', + (invariants) => invariants.concat([invariant]) + ); +} + +export function addExpectation(world: World, expectation: Expectation): World { + return world.update( + 'expectations', + (expectations) => expectations.concat([expectation]) + ); +} + +function getInvariantFilter(type: string) { + let filters: {[filter: string]: (invariant: Invariant) => boolean} = { + all: (_invariant) => true, + success: (invariant) => !(invariant instanceof SuccessInvariant), + remains: (invariant) => !(invariant instanceof RemainsInvariant), + static: (invariant) => !(invariant instanceof StaticInvariant) + }; + + let filter = filters[type.toLowerCase()]; + + if (!filter) { + throw new Error(`Unknown invariant type \`${type}\` when wiping invariants.`); + } + + return filter; +} + +export function clearInvariants(world: World, type: string): World { + let filter = getInvariantFilter(type); + + return world.update( + 'invariants', + (invariants) => world.invariants.filter(filter) + ); +} + +export function holdInvariants(world: World, type: string): World { + let filter = getInvariantFilter(type); + + return world.update('invariants', (invariants) => { + return world.invariants.map((invariant) => { + if (filter(invariant)) { + invariant.held = true; + } + + return invariant; + }); + }); +} + +export async function checkExpectations(world: World): Promise { + if (!world.get('newInvokation')) { + return world; + } else { + // Lastly, check invariants each hold + await Promise.all(world.get('expectations').map((expectation) => { + // Check the expectation holds + return expectation.checker(world); + })); + + return world.set('expectations', []); + } +} + +export async function checkInvariants(world: World): Promise { + if (!world.get('newInvokation')) { + return world; + } else { + // Lastly, check invariants each hold + await Promise.all(world.get('invariants').map((invariant) => { + // Check the invariant still holds + if (!invariant.held) { + return invariant.checker(world); + } + })); + + // Remove holds + return world.update('invariants', (invariants) => { + return invariants.map((invariant) => { + invariant.held = false; + + return invariant; + }); + }); + } +} + +export function describeUser(world: World, address: string): string { + // Look up by alias + let alias = Object.entries(world.settings.aliases).find(([name, aliasAddr]) => aliasAddr === address); + if (alias) { + return alias[0]; + } + + // Look up by `from` + if (world.settings.from === address) { + return 'root'; + } + + // Look up by unlocked accounts + let account = world.accounts.find((account) => account.address === address); + if (account) { + return account.name; + } + + // Otherwise, just return the address itself + return address; +} + +// Fails an assertion with reason +export function fail(world: World, reason: string): World { + if (world.event) { + world.assert.fail(0, 1, `${reason} processing ${formatEvent(world.event)}`); + } else { + world.assert.fail(0, 1, reason); + } + + return world; +} diff --git a/scenario/tsconfig.json b/scenario/tsconfig.json new file mode 100644 index 000000000..ef2183052 --- /dev/null +++ b/scenario/tsconfig.json @@ -0,0 +1,63 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "es2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "lib": ["esnext"], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./.tsbuilt", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + }, + "include": [ + "./src/**/*" + ] +} diff --git a/scenario/webpack.config.js b/scenario/webpack.config.js new file mode 100644 index 000000000..e25a1fbae --- /dev/null +++ b/scenario/webpack.config.js @@ -0,0 +1,28 @@ +'use strict' +const webpack = require('webpack'); + +module.exports = { + stats: 'verbose', + devtool: 'source-map', + externals: { + file: '{}', + fs: '{}', + tls: '{}', + net: '{}', + xmlhttprequest: '{}', + 'truffle-flattener': '{}', + 'request': '{}' + }, + optimization: { + minimize: true + }, + plugins: [ + new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), + new webpack.DefinePlugin({ + 'process.env': { + // This has effect on the react lib size + 'NODE_ENV': JSON.stringify('production'), + } + }) + ] +} diff --git a/scenario/yarn.lock b/scenario/yarn.lock new file mode 100644 index 000000000..d34536cf9 --- /dev/null +++ b/scenario/yarn.lock @@ -0,0 +1,5093 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@resolver-engine/core@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@resolver-engine/core/-/core-0.2.1.tgz#0d71803f6d3b8cb2e9ed481a1bf0ca5f5256d0c0" + integrity sha512-nsLQHmPJ77QuifqsIvqjaF5B9aHnDzJjp73Q1z6apY3e9nqYrx4Dtowhpsf7Jwftg/XzVDEMQC+OzUBNTS+S1A== + dependencies: + debug "^3.1.0" + request "^2.85.0" + +"@resolver-engine/fs@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@resolver-engine/fs/-/fs-0.2.1.tgz#f98a308d77568cc02651d03636f46536b941b241" + integrity sha512-7kJInM1Qo2LJcKyDhuYzh9ZWd+mal/fynfL9BNjWOiTcOpX+jNfqb/UmGUqros5pceBITlWGqS4lU709yHFUbg== + dependencies: + "@resolver-engine/core" "^0.2.1" + debug "^3.1.0" + +"@resolver-engine/imports-fs@^0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@resolver-engine/imports-fs/-/imports-fs-0.2.2.tgz#5a81ef3285dbf0411ab3b15205080a1ad7622d9e" + integrity sha512-gFCgMvCwyppjwq0UzIjde/WI+yDs3oatJhozG9xdjJdewwtd7LiF0T5i9lrHAUtqrQbqoFE4E+ZMRVHWpWHpKQ== + dependencies: + "@resolver-engine/fs" "^0.2.1" + "@resolver-engine/imports" "^0.2.2" + debug "^3.1.0" + +"@resolver-engine/imports@^0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@resolver-engine/imports/-/imports-0.2.2.tgz#d3de55a1bb5f3beb7703fdde743298f321175843" + integrity sha512-u5/HUkvo8q34AA+hnxxqqXGfby5swnH0Myw91o3Sm2TETJlNKXibFGSKBavAH+wvWdBi4Z5gS2Odu0PowgVOUg== + dependencies: + "@resolver-engine/core" "^0.2.1" + debug "^3.1.0" + hosted-git-info "^2.6.0" + +"@types/node@^10.3.2": + version "10.14.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.4.tgz#1c586b991457cbb58fef51bc4e0cfcfa347714b5" + integrity sha512-DT25xX/YgyPKiHFOpNuANIQIVvYEwCWXgK2jYYwqgaMrYE6+tq+DtmMwlD3drl6DJbUwtlIDnn0d7tIn/EbXBg== + +"@webassemblyjs/ast@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" + integrity sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ== + dependencies: + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/wast-parser" "1.8.5" + +"@webassemblyjs/floating-point-hex-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721" + integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== + +"@webassemblyjs/helper-api-error@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7" + integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== + +"@webassemblyjs/helper-buffer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204" + integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== + +"@webassemblyjs/helper-code-frame@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e" + integrity sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ== + dependencies: + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/helper-fsm@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452" + integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== + +"@webassemblyjs/helper-module-context@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245" + integrity sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g== + dependencies: + "@webassemblyjs/ast" "1.8.5" + mamacro "^0.0.3" + +"@webassemblyjs/helper-wasm-bytecode@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61" + integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== + +"@webassemblyjs/helper-wasm-section@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf" + integrity sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + +"@webassemblyjs/ieee754@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e" + integrity sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10" + integrity sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc" + integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== + +"@webassemblyjs/wasm-edit@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a" + integrity sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/helper-wasm-section" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-opt" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + "@webassemblyjs/wast-printer" "1.8.5" + +"@webassemblyjs/wasm-gen@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc" + integrity sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wasm-opt@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264" + integrity sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-buffer" "1.8.5" + "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + +"@webassemblyjs/wasm-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d" + integrity sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-wasm-bytecode" "1.8.5" + "@webassemblyjs/ieee754" "1.8.5" + "@webassemblyjs/leb128" "1.8.5" + "@webassemblyjs/utf8" "1.8.5" + +"@webassemblyjs/wast-parser@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c" + integrity sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/floating-point-hex-parser" "1.8.5" + "@webassemblyjs/helper-api-error" "1.8.5" + "@webassemblyjs/helper-code-frame" "1.8.5" + "@webassemblyjs/helper-fsm" "1.8.5" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/wast-printer@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc" + integrity sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/wast-parser" "1.8.5" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +acorn-dynamic-import@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" + integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw== + +acorn-walk@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.1.1.tgz#d363b66f5fac5f018ff9c3a1e7b6f8e310cc3913" + integrity sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw== + +acorn@^6.0.5, acorn@^6.0.7: + version "6.1.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" + integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== + +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + integrity sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0= + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.0.tgz#4b831e7b531415a7cc518cd404e73f6193c6349d" + integrity sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw== + +ajv@^6.1.0, ajv@^6.5.5: + version "6.10.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" + integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +any-promise@1.3.0, any-promise@^1.0.0, any-promise@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +aproba@^1.0.3, aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= + dependencies: + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.2.tgz#8b8a7ca2a658f927e9f307d6d1a42f4199f0f735" + integrity sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg== + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-js@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +bfj@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/bfj/-/bfj-6.1.1.tgz#05a3b7784fbd72cfa3c22e56002ef99336516c48" + integrity sha512-+GUNvzHR4nRyGybQc2WpNJL4MJazMuvf92ueIyA0bIkPRwhhQu3IfZQ2PSoVPpCBJfmoSdOxu5rnotfFLlvYRQ== + dependencies: + bluebird "^3.5.1" + check-types "^7.3.0" + hoopy "^0.1.2" + tryer "^1.0.0" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +bignumber.js@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-8.0.1.tgz#5d419191370fb558c64e3e5f70d68e5947138832" + integrity sha512-zAySveTJXkgLYCBi0b14xzfnOs+f3G6x36I8w2a1+PFQpWk/dp0mI0F+ZZK2bu+3ELewDcSyP+Cfq++NcHX7sg== + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +bindings@^1.3.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= + dependencies: + inherits "~2.0.0" + +bluebird@^2.9.34: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE= + +bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.3: + version "3.5.4" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.4.tgz#d6cc661595de30d5b3af5fcedd3c0b3ef6ec5714" + integrity sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw== + +bn.js@4.11.6: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + integrity sha1-UzRK2xRhehP26N0s4okF0cC6MhU= + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.11.6, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + +body-parser@1.18.3, body-parser@^1.16.0: + version "1.18.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" + on-finished "~2.3.0" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browser-stdout@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" + integrity sha1-81HTKWnTL6XXpVZxVCY9korjvR8= + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sha3@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/browserify-sha3/-/browserify-sha3-0.0.4.tgz#086c47b8c82316c9d47022c26185954576dd8e26" + integrity sha1-CGxHuMgjFsnUcCLCYYWVRXbdjiY= + dependencies: + js-sha3 "^0.6.1" + safe-buffer "^5.1.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-to-arraybuffer@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" + integrity sha1-YGSkD6dutDxyOrqe+PbhIW0QURo= + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +buffer@^5.0.5, buffer@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.1.tgz#dd57fa0f109ac59c602479044dca7b8b3d0b71d6" + integrity sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +cacache@^11.0.2: + version "11.3.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.2.tgz#2d81e308e3d258ca38125b676b98b2ac9ce69bfa" + integrity sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg== + dependencies: + bluebird "^3.5.3" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.3" + graceful-fs "^4.1.15" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@^2.3.0, chalk@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +check-types@^7.3.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/check-types/-/check-types-7.4.0.tgz#0378ec1b9616ec71f774931a3c6516fad8c152f4" + integrity sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg== + +chokidar@^2.0.2: + version "2.1.5" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.5.tgz#0ae8434d962281a5f56c72869e79cb6d9d86ad4d" + integrity sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== + +chrome-trace-event@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" + integrity sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A== + dependencies: + tslib "^1.9.0" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" + integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== + dependencies: + delayed-stream "~1.0.0" + +commander@2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== + +commander@^2.18.0, commander@^2.19.0, commander@^2.8.1: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + +commander@~2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ= + dependencies: + graceful-readlink ">= 1.0.0" + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + +cookiejar@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" + integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cors@^2.8.1: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-browserify@3.12.0, crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= + +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +decamelize@^1.1.1, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +decompress-response@^3.2.0, decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" + integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== + dependencies: + file-type "^5.2.0" + is-stream "^1.1.0" + tar-stream "^1.5.2" + +decompress-tarbz2@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" + integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== + dependencies: + decompress-tar "^4.1.0" + file-type "^6.1.0" + is-stream "^1.1.0" + seek-bzip "^1.0.5" + unbzip2-stream "^1.0.9" + +decompress-targz@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" + integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== + dependencies: + decompress-tar "^4.1.1" + file-type "^5.2.0" + is-stream "^1.1.0" + +decompress-unzip@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" + integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= + dependencies: + file-type "^3.8.0" + get-stream "^2.2.0" + pify "^2.3.0" + yauzl "^2.4.2" + +decompress@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.0.tgz#7aedd85427e5a92dacfe55674a7c505e96d01f9d" + integrity sha1-eu3YVCflqS2s/lVnSnxQXpbQH50= + dependencies: + decompress-tar "^4.0.0" + decompress-tarbz2 "^4.0.0" + decompress-targz "^4.0.0" + decompress-unzip "^4.0.1" + graceful-fs "^4.1.10" + make-dir "^1.0.0" + pify "^2.3.0" + strip-dirs "^2.0.0" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +define-properties@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-file@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +diff@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" + integrity sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dom-walk@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" + integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg= + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +duplexer@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +ejs@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0" + integrity sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ== + +elliptic@6.3.3: + version "6.3.3" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.3.tgz#5482d9646d54bcb89fd7d994fc9e2e9568876e3f" + integrity sha1-VILZZG1UvLif19mU/J4ulWiHbj8= + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + inherits "^2.0.1" + +elliptic@^6.0.0, elliptic@^6.4.0: + version "6.4.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" + integrity sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ== + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + +errno@^0.1.3, errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== + dependencies: + prr "~1.0.1" + +es-abstract@^1.5.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" + integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== + dependencies: + es-to-primitive "^1.2.0" + function-bind "^1.1.1" + has "^1.0.3" + is-callable "^1.1.4" + is-regex "^1.0.4" + object-keys "^1.0.12" + +es-to-primitive@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" + integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +eslint-scope@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== + dependencies: + estraverse "^4.1.0" + +estraverse@^4.1.0, estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eth-ens-namehash@2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" + integrity sha1-IprEbsqG1S4MmR58sq74P/D2i88= + dependencies: + idna-uts46-hx "^2.3.1" + js-sha3 "^0.5.7" + +eth-lib@0.1.27, eth-lib@^0.1.26: + version "0.1.27" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.27.tgz#f0b0fd144f865d2d6bf8257a40004f2e75ca1dd6" + integrity sha512-B8czsfkJYzn2UIEMwjc7Mbj+Cy72V+/OXH/tb44LV8jhrjizQJJ325xMOMyk3+ETa6r6oi0jsUY14+om8mQMWA== + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + keccakjs "^0.2.1" + nano-json-stream-parser "^0.1.2" + servify "^0.1.12" + ws "^3.0.0" + xhr-request-promise "^0.1.2" + +eth-lib@0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.7.tgz#2f93f17b1e23aec3759cd4a3fe20c1286a3fc1ca" + integrity sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco= + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + xhr-request-promise "^0.1.2" + +ethers@4.0.0-beta.1: + version "4.0.0-beta.1" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.0-beta.1.tgz#0648268b83e0e91a961b1af971c662cdf8cbab6d" + integrity sha512-SoYhktEbLxf+fiux5SfCEwdzWENMvgIbMZD90I62s4GZD9nEjgEWy8ZboI3hck193Vs0bDoTohDISx84f2H2tw== + dependencies: + "@types/node" "^10.3.2" + aes-js "3.0.0" + bn.js "^4.4.0" + elliptic "6.3.3" + hash.js "1.1.3" + js-sha3 "0.5.7" + scrypt-js "2.0.3" + setimmediate "1.0.4" + uuid "2.0.1" + xmlhttprequest "1.8.0" + +ethers@^4.0.0-beta.1: + version "4.0.27" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.27.tgz#e570b0da9d805ad65c83d81919abe02b2264c6bf" + integrity sha512-+DXZLP/tyFnXWxqr2fXLT67KlGUfLuvDkHSOtSC9TUVG9OIj6yrG5JPeXRMYo15xkOYwnjgdMKrXp5V94rtjJA== + dependencies: + "@types/node" "^10.3.2" + aes-js "3.0.0" + bn.js "^4.4.0" + elliptic "6.3.3" + hash.js "1.1.3" + js-sha3 "0.5.7" + scrypt-js "2.0.4" + setimmediate "1.0.4" + uuid "2.0.1" + xmlhttprequest "1.8.0" + +ethjs-unit@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" + integrity sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk= + dependencies: + bn.js "4.11.6" + number-to-bn "1.7.0" + +eventemitter3@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.1.1.tgz#47786bdaa087caf7b1b75e73abc5c7d540158cd0" + integrity sha1-R3hr2qCHyvext15zq8XH1UAVjNA= + +events@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" + integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= + dependencies: + homedir-polyfill "^1.0.1" + +express@^4.14.0, express@^4.16.3: + version "4.16.4" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" + integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.3" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.1" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.4" + qs "6.5.2" + range-parser "~1.2.0" + safe-buffer "5.1.2" + send "0.16.2" + serve-static "1.13.2" + setprototypeof "1.1.0" + statuses "~1.4.0" + type-is "~1.6.16" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" + +figgy-pudding@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== + +file-type@^3.8.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" + integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= + +file-type@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" + integrity sha1-LdvqfHP/42No365J3DOMBYwritY= + +file-type@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" + integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +filesize@^3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" + integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.4.0" + unpipe "~1.0.0" + +find-cache-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +findup-sync@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" + integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw= + dependencies: + detect-file "^1.0.0" + is-glob "^3.1.0" + micromatch "^3.0.4" + resolve-dir "^1.0.1" + +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-extra@^2.0.0, fs-extra@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" + integrity sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU= + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== + dependencies: + minipass "^2.2.1" + +fs-promise@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fs-promise/-/fs-promise-2.0.3.tgz#f64e4f854bcf689aa8bddcba268916db3db46854" + integrity sha1-9k5PhUvPaJqovdy6JokW2z20aFQ= + dependencies: + any-promise "^1.3.0" + fs-extra "^2.0.0" + mz "^2.6.0" + thenify-all "^1.6.0" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" + integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +fstream@^1.0.2, fstream@^1.0.8: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.0.2, function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-stream@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" + integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= + dependencies: + object-assign "^4.0.1" + pinkie-promise "^2.0.0" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + +global@~4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" + integrity sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8= + dependencies: + min-document "^2.19.0" + process "~0.5.1" + +got@7.1.0, got@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" + integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== + dependencies: + decompress-response "^3.2.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-plain-obj "^1.1.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + p-cancelable "^0.3.0" + p-timeout "^1.1.1" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + url-parse-lax "^1.0.0" + url-to-options "^1.0.1" + +graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= + +growl@1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" + integrity sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q== + +gzip-size@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.0.0.tgz#a55ecd99222f4c48fd8c01c625ce3b349d0a0e80" + integrity sha512-5iI7omclyqrnWw4XbXAmGhPsABkSIDQonv2K0h61lybgofWa6iZyvrI3r2zsJH4P8Nb64fFVzlvfhs0g7BBxAA== + dependencies: + duplexer "^0.1.1" + pify "^3.0.0" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-symbol-support-x@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== + +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= + +has-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== + dependencies: + has-symbol-support-x "^1.4.1" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.1, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + integrity sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +he@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== + dependencies: + parse-passwd "^1.0.0" + +hoopy@^0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" + integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ== + +hosted-git-info@^2.6.0: + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== + +http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-https@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" + integrity sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs= + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +iconv-lite@0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +idna-uts46-hx@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" + integrity sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA== + dependencies: + punycode "2.1.0" + +ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== + dependencies: + minimatch "^3.0.4" + +immutable@^4.0.0-rc.12: + version "4.0.0-rc.12" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0-rc.12.tgz#ca59a7e4c19ae8d9bf74a97bdf0f6e2f2a5d0217" + integrity sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A== + +import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +ini@^1.3.4, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +interpret@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4= + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.3, is-callable@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-function@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" + integrity sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU= + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" + integrity sha1-fY035q135dEnFIkTxXPggtd39VQ= + +is-natural-number@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" + integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" + integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= + +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= + dependencies: + has "^1.0.1" + +is-retry-allowed@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ= + +is-stream@^1.0.0, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-symbol@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" + integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== + dependencies: + has-symbols "^1.0.0" + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-windows@^1.0.1, is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== + dependencies: + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" + +js-sha3@0.5.7, js-sha3@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" + integrity sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc= + +js-sha3@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.6.1.tgz#5b89f77a7477679877f58c4a075240934b1f95c0" + integrity sha1-W4n3enR3Z5h39YxKB1JAk0sflcA= + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + integrity sha1-NzaitCi4e72gzIO1P6PWM6NcKug= + optionalDependencies: + graceful-fs "^4.1.6" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +keccakjs@^0.2.1: + version "0.2.3" + resolved "https://registry.yarnpkg.com/keccakjs/-/keccakjs-0.2.3.tgz#5e4e969ce39689a3861f445d7752ee3477f9fe72" + integrity sha512-BjLkNDcfaZ6l8HBG9tH0tpmDv3sS2mA7FNQxFHpCdzP3Gb2MVruXBSuoM66SnVxKJpAr5dKGdkHD+bDokt8fTg== + dependencies: + browserify-sha3 "^0.0.4" + sha3 "^1.2.2" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + dependencies: + invert-kv "^1.0.0" + +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + +loader-runner@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== + +loader-utils@^1.0.2, loader-utils@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== + dependencies: + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lodash@^4.17.10: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== + dependencies: + pify "^3.0.0" + +make-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +mamacro@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" + integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA== + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= + dependencies: + mimic-fn "^1.0.0" + +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +memory-fs@^0.4.0, memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@~1.38.0: + version "1.38.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad" + integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg== + +mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.18, mime-types@~2.1.19: + version "2.1.22" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd" + integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog== + dependencies: + mime-db "~1.38.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= + dependencies: + dom-walk "^0.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +minipass@^2.2.1, minipass@^2.3.4: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp-promise@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" + integrity sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE= + dependencies: + mkdirp "*" + +mkdirp@*, mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +mocha@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794" + integrity sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA== + dependencies: + browser-stdout "1.3.0" + commander "2.11.0" + debug "3.1.0" + diff "3.3.1" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.3" + he "1.1.1" + mkdirp "0.5.1" + supports-color "4.4.0" + +mock-fs@^4.1.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.8.0.tgz#eb0784ceba4b34c91a924a5112eeb36e1b5a9e29" + integrity sha512-Gwj4KnJOW15YeTJKO5frFd/WDO5Mc0zxXqL9oHx3+e9rBqW8EVARqQHSaIXznUdljrD6pvbNGW2ZGXKPEfYJfw== + +mout@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/mout/-/mout-0.11.1.tgz#ba3611df5f0e5b1ffbfd01166b8f02d1f5fa2b99" + integrity sha1-ujYR318OWx/7/QEWa48C0fX6K5k= + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +mz@^2.6.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nan@2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA== + +nan@^2.0.8, nan@^2.11.0, nan@^2.3.3, nan@^2.9.2: + version "2.13.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7" + integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw== + +nano-json-stream-parser@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" + integrity sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18= + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" + integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA== + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= + +neo-async@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" + integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-libs-browser@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.0.tgz#c72f60d9d46de08a940dedbb25f3ffa2f9bbaa77" + integrity sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^3.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.0" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.11.0" + vm-browserify "0.0.4" + +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-bundled@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" + integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + +npm-packlist@^1.1.6: + version "1.4.1" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc" + integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +number-to-bn@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" + integrity sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA= + dependencies: + bn.js "4.11.6" + strip-hex-prefix "1.0.0" + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-keys@^1.0.12: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.0.tgz#11bd22348dd2e096a045ab06f6c85bcc340fa032" + integrity sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +oboe@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.3.tgz#2b4865dbd46be81225713f4e9bfe4bcf4f680a4f" + integrity sha1-K0hl29Rr6BIlcT9Om/5Lz09oCk8= + dependencies: + http-https "^1.0.0" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +opener@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed" + integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA== + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-locale@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +os-tmpdir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-is-promise@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5" + integrity sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg== + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" + integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== + dependencies: + p-try "^2.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-timeout@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" + integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= + dependencies: + p-finally "^1.0.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pako@~1.0.5: + version "1.0.10" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" + integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== + +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY= + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parse-asn1@^5.0.0: + version "5.1.4" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc" + integrity sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw== + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-headers@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.2.tgz#9545e8a4c1ae5eaea7d24992bca890281ed26e34" + integrity sha512-/LypJhzFmyBIDYP9aDVgeyEb5sQfbfY5mnDq4hVhlQ69js87wXfmEI5V3xI6vvXasqebp0oCytYFLxsBVfCzSg== + dependencies: + for-each "^0.3.3" + string.prototype.trim "^1.1.2" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= + +parseurl@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + integrity sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo= + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +pbkdf2@^3.0.3: + version "3.0.17" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +pegjs@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/pegjs/-/pegjs-0.10.0.tgz#cf8bafae6eddff4b5a7efb185269eaaf4610ddbd" + integrity sha1-z4uvrm7d/0tafvsYUmnqr0YQ3b0= + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +process@~0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" + integrity sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8= + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +proxy-addr@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.8.0" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.24: + version "1.1.31" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" + integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + integrity sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0= + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@6.5.2, qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +randomhex@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/randomhex/-/randomhex-0.1.5.tgz#baceef982329091400f2a2912c6cd02f1094f585" + integrity sha1-us7vmCMpCRQA8qKRLGzQLxCU9YU= + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== + dependencies: + bytes "3.0.0" + http-errors "1.6.3" + iconv-lite "0.4.23" + unpipe "1.0.0" + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +request@^2.79.0, request@^2.85.0, request@^2.88.0: + version "2.88.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.0" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.4.3" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= + dependencies: + resolve-from "^3.0.0" + +resolve-dir@^1.0.0, resolve-dir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +rimraf@2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +scrypt-js@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.3.tgz#bb0040be03043da9a012a2cea9fc9f852cfc87d4" + integrity sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q= + +scrypt-js@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.4.tgz#32f8c5149f0797672e551c07e230f834b6af5f16" + integrity sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw== + +scrypt.js@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/scrypt.js/-/scrypt.js-0.2.0.tgz#af8d1465b71e9990110bedfc593b9479e03a8ada" + integrity sha1-r40UZbcemZARC+38WTuUeeA6ito= + dependencies: + scrypt "^6.0.2" + scryptsy "^1.2.1" + +scrypt@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/scrypt/-/scrypt-6.0.3.tgz#04e014a5682b53fa50c2d5cce167d719c06d870d" + integrity sha1-BOAUpWgrU/pQwtXM4WfXGcBthw0= + dependencies: + nan "^2.0.8" + +scryptsy@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" + integrity sha1-oyJfpLJST4AnAHYeKFW987LZIWM= + dependencies: + pbkdf2 "^3.0.3" + +seek-bzip@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc" + integrity sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w= + dependencies: + commander "~2.8.1" + +semver@^5.0.1, semver@^5.3.0, semver@^5.5.0, semver@^5.6.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" + integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== + +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serialize-javascript@^1.4.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.6.1.tgz#4d1f697ec49429a847ca6f442a2a755126c4d879" + integrity sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw== + +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +servify@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" + integrity sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw== + dependencies: + body-parser "^1.16.0" + cors "^2.8.1" + express "^4.14.0" + request "^2.79.0" + xhr "^2.3.3" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f" + integrity sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48= + +setimmediate@^1.0.4, setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +sha3@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/sha3/-/sha3-1.2.2.tgz#a66c5098de4c25bc88336ec8b4817d005bca7ba9" + integrity sha1-pmxQmN5MJbyIM27ItIF9AFvKe6k= + dependencies: + nan "2.10.0" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +simple-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" + integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY= + +simple-get@^2.7.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" + integrity sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw== + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +solidity-parser-antlr@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/solidity-parser-antlr/-/solidity-parser-antlr-0.4.2.tgz#b862eba5936e7a90b4f5f1c8eb1d33fe86650f78" + integrity sha512-0OKT2YKZAqPe14HN7Nbo24hjmnyUYh92UjyZG0Zz2rpQhl/w8asX8qHb+ASSXfayQaiW8g9zGIupXEE355tOQQ== + +solparse@^2.2.8: + version "2.2.8" + resolved "https://registry.yarnpkg.com/solparse/-/solparse-2.2.8.tgz#d13e42dbed95ce32f43894f5ec53f00d14cf9f11" + integrity sha512-Tm6hdfG72DOxD40SD+T5ddbekWglNWjzDRSNq7ZDIOHVsyaJSeeunUuWNj4DE7uDrJK3tGQuX0ZTDZWNYsGPMA== + dependencies: + mocha "^4.0.1" + pegjs "^0.10.0" + yargs "^10.0.3" + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@~0.5.10: + version "0.5.11" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.11.tgz#efac2ce0800355d026326a0ca23e162aeac9a4e2" + integrity sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== + dependencies: + figgy-pudding "^3.5.1" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== + +stream-browserify@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string.prototype.trim@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea" + integrity sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.0" + function-bind "^1.0.2" + +string_decoder@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-dirs@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" + integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== + dependencies: + is-natural-number "^4.0.1" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" + integrity sha1-DF8VX+8RUTczd96du1iNoFUA428= + dependencies: + is-hex-prefixed "1.0.0" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +supports-color@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" + integrity sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ== + dependencies: + has-flag "^2.0.0" + +supports-color@^5.3.0, supports-color@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +swarm-js@0.1.37: + version "0.1.37" + resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.37.tgz#27d485317a340bbeec40292af783cc10acfa4663" + integrity sha512-G8gi5fcXP/2upwiuOShJ258sIufBVztekgobr3cVgYXObZwJ5AXLqZn52AI+/ffft29pJexF9WNdUxjlkVehoQ== + dependencies: + bluebird "^3.5.0" + buffer "^5.0.5" + decompress "^4.0.0" + eth-lib "^0.1.26" + fs-extra "^2.1.2" + fs-promise "^2.0.0" + got "^7.1.0" + mime-types "^2.1.16" + mkdirp-promise "^5.0.1" + mock-fs "^4.1.0" + setimmediate "^1.0.5" + tar.gz "^1.0.5" + xhr-request-promise "^0.1.2" + +tapable@^1.0.0, tapable@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.1.tgz#4d297923c5a72a42360de2ab52dadfaaec00018e" + integrity sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA== + +tar-stream@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + +tar.gz@^1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/tar.gz/-/tar.gz-1.0.7.tgz#577ef2c595faaa73452ef0415fed41113212257b" + integrity sha512-uhGatJvds/3diZrETqMj4RxBR779LKlIE74SsMcn5JProZsfs9j0QBwWO1RW+IWNJxS2x8Zzra1+AW6OQHWphg== + dependencies: + bluebird "^2.9.34" + commander "^2.8.1" + fstream "^1.0.8" + mout "^0.11.0" + tar "^2.1.1" + +tar@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +tar@^4: + version "4.4.8" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" + integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.4" + minizlib "^1.1.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +terser-webpack-plugin@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz#3f98bc902fac3e5d0de730869f50668561262ec8" + integrity sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA== + dependencies: + cacache "^11.0.2" + find-cache-dir "^2.0.0" + schema-utils "^1.0.0" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + terser "^3.16.1" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + +terser@^3.16.1: + version "3.17.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-3.17.0.tgz#f88ffbeda0deb5637f9d24b0da66f4e15ab10cb2" + integrity sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ== + dependencies: + commander "^2.19.0" + source-map "~0.6.1" + source-map-support "~0.5.10" + +thenify-all@^1.0.0, thenify-all@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.0" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839" + integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk= + dependencies: + any-promise "^1.0.0" + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +timed-out@^4.0.0, timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= + +timers-browserify@^2.0.4: + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg== + dependencies: + setimmediate "^1.0.4" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +tough-cookie@~2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== + dependencies: + psl "^1.1.24" + punycode "^1.4.1" + +truffle-flattener@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/truffle-flattener/-/truffle-flattener-1.3.0.tgz#a5b0340897e32cf8389fea105b52fa93c335f04c" + integrity sha512-ppJ9xI0tDuvCYjQlcWwMBcOKZph5U4YpG/gChyUVDxOjUIniG5g7y9vZho2PRj1FohPPnOjg1KOAVNlk/bPZrw== + dependencies: + "@resolver-engine/imports-fs" "^0.2.2" + find-up "^2.1.0" + mkdirp "^0.5.1" + solidity-parser-antlr "^0.4.0" + tsort "0.0.1" + +truffle-hdwallet-provider@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/truffle-hdwallet-provider/-/truffle-hdwallet-provider-1.0.5.tgz#76059fb37d13df70bf37a9c296cf27d5a944e112" + integrity sha512-T9qNm7b6MD0UPWVmmJEhgzW1DdR6mkMDijGBSbdJqYaaBLufoycE+qH3dsV+m1mLTE+ebM5RcJ4gF4oXgDW67w== + dependencies: + any-promise "^1.3.0" + bindings "^1.3.1" + websocket "^1.0.28" + +tryer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" + integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== + +ts-loader@^5.3.3: + version "5.3.3" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-5.3.3.tgz#8b4af042e773132d86b3c99ef0acf3b4d325f473" + integrity sha512-KwF1SplmOJepnoZ4eRIloH/zXL195F51skt7reEsS6jvDqzgc/YSbz9b8E07GxIUwLXdcD4ssrJu6v8CwaTafA== + dependencies: + chalk "^2.3.0" + enhanced-resolve "^4.0.0" + loader-utils "^1.0.2" + micromatch "^3.1.4" + semver "^5.0.1" + +ts-pegjs@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/ts-pegjs/-/ts-pegjs-0.2.2.tgz#f4ae6cc277133083858033badf6991a12a400f7c" + integrity sha512-7PUw/w9pFNk/kiv1x7e2lu4WUetQYnaCXjxiRJTEWoLSXpjsg8VKMZpUwa+zACNuWPCL7tcI+1IaC9mm3Pqb7Q== + dependencies: + pegjs "^0.10.0" + +tslib@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== + +tsort@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" + integrity sha1-4igPXoF/i/QnVlf9D5rr1E9aJ4Y= + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-is@~1.6.16: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +typedarray-to-buffer@^3.1.2, typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +typescript@^3.3.3: + version "3.4.1" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.1.tgz#b6691be11a881ffa9a05765a205cb7383f3b63c6" + integrity sha512-3NSMb2VzDQm8oBTLH6Nj55VVtUEpe/rgkIzMir0qVoLyjDZlnMBva0U6vDiV3IH+sl/Yu6oP5QwsAQtHPmDd2Q== + +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== + +unbzip2-stream@^1.0.9: + version "1.3.3" + resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz#d156d205e670d8d8c393e1c02ebd506422873f6a" + integrity sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg== + dependencies: + buffer "^5.2.1" + through "^2.3.8" + +underscore@1.8.3: + version "1.8.3" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + integrity sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI= + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6" + integrity sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg== + dependencies: + imurmurhash "^0.1.4" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" + integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= + dependencies: + prepend-http "^1.0.1" + +url-set-query@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" + integrity sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk= + +url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +utf8@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.1.tgz#2e01db02f7d8d0944f77104f1609eb0c304cf768" + integrity sha1-LgHbAvfY0JRPdxBPFgnrDDBM92g= + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac" + integrity sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w= + +uuid@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + +v8-compile-cache@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c" + integrity sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + integrity sha1-XX6kW7755Kb/ZflUOOCofDV9WnM= + dependencies: + indexof "0.0.1" + +watchpack@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== + dependencies: + chokidar "^2.0.2" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +web3-bzz@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.0.0-beta.37.tgz#59e3e4f5a9d732731008fe9165c3ec8bf85d502f" + integrity sha512-E+dho49Nsm/QpQvYWOF35YDsQrMvLB19AApENxhlQsu6HpWQt534DQul0t3Y/aAh8rlKD6Kanxt8LhHDG3vejQ== + dependencies: + got "7.1.0" + swarm-js "0.1.37" + underscore "1.8.3" + +web3-core-helpers@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.37.tgz#04ec354b7f5c57234c309eea2bda9bf1f2fe68ba" + integrity sha512-efaLOzN28RMnbugnyelgLwPWWaSwElQzcAJ/x3PZu+uPloM/lE5x0YuBKvIh7/PoSMlHqtRWj1B8CpuQOUQ5Ew== + dependencies: + underscore "1.8.3" + web3-eth-iban "1.0.0-beta.37" + web3-utils "1.0.0-beta.37" + +web3-core-method@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.0.0-beta.37.tgz#53d148e63f818b23461b26307afdfbdaa9457744" + integrity sha512-pKWFUeqnVmzx3VrZg+CseSdrl/Yrk2ioid/HzolNXZE6zdoITZL0uRjnsbqXGEzgRRd1Oe/pFndpTlRsnxXloA== + dependencies: + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.37" + web3-core-promievent "1.0.0-beta.37" + web3-core-subscriptions "1.0.0-beta.37" + web3-utils "1.0.0-beta.37" + +web3-core-promievent@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.0.0-beta.37.tgz#4e51c469d0a7ac0a969885a4dbcde8504abe5b02" + integrity sha512-GTF2r1lP8nJBeA5Gxq5yZpJy9l8Fb9CXGZPfF8jHvaRdQHtm2Z+NDhqYmF833lcdkokRSyfPcXlz1mlWeClFpg== + dependencies: + any-promise "1.3.0" + eventemitter3 "1.1.1" + +web3-core-requestmanager@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.0.0-beta.37.tgz#721a75df5920621bff42d9d74f7a64413675d56b" + integrity sha512-66VUqye5BGp1Zz1r8psCxdNH+GtTjaFwroum2Osx+wbC5oRjAiXkkadiitf6wRb+edodjEMPn49u7B6WGNuewQ== + dependencies: + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.37" + web3-providers-http "1.0.0-beta.37" + web3-providers-ipc "1.0.0-beta.37" + web3-providers-ws "1.0.0-beta.37" + +web3-core-subscriptions@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.37.tgz#40de5e2490cc05b15faa8f935c97fd48d670cd9a" + integrity sha512-FdXl8so9kwkRRWziuCSpFsAuAdg9KvpXa1fQlT16uoGcYYfxwFO/nkwyBGQzkZt7emShI2IRugcazyPCZDwkOA== + dependencies: + eventemitter3 "1.1.1" + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.37" + +web3-core@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.0.0-beta.37.tgz#66c2c7000772c9db36d737ada31607ace09b7e90" + integrity sha512-cIwEqCj7OJyefQNauI0HOgW4sSaOQ98V99H2/HEIlnCZylsDzfw7gtQUdwnRFiIyIxjbWy3iWsjwDPoXNPZBYg== + dependencies: + web3-core-helpers "1.0.0-beta.37" + web3-core-method "1.0.0-beta.37" + web3-core-requestmanager "1.0.0-beta.37" + web3-utils "1.0.0-beta.37" + +web3-eth-abi@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.37.tgz#55592fa9cd2427d9f0441d78f3b8d0c1359a2a24" + integrity sha512-g9DKZGM2OqwKp/tX3W/yihcj7mQCtJ6CXyZXEIZfuDyRBED/iSEIFfieDOd+yo16sokLMig6FG7ADhhu+19hdA== + dependencies: + ethers "4.0.0-beta.1" + underscore "1.8.3" + web3-utils "1.0.0-beta.37" + +web3-eth-accounts@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.37.tgz#0a5a9f14a6c3bd285e001c15eb3bb38ffa4b5204" + integrity sha512-uvbHL62/zwo4GDmwKdqH9c/EgYd8QVnAfpVw8D3epSISpgbONNY7Hr4MRMSd/CqAP12l2Ls9JVQGLhhC83bW6g== + dependencies: + any-promise "1.3.0" + crypto-browserify "3.12.0" + eth-lib "0.2.7" + scrypt.js "0.2.0" + underscore "1.8.3" + uuid "2.0.1" + web3-core "1.0.0-beta.37" + web3-core-helpers "1.0.0-beta.37" + web3-core-method "1.0.0-beta.37" + web3-utils "1.0.0-beta.37" + +web3-eth-contract@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.37.tgz#87f93c95ed16f320ba54943b7886890de6766013" + integrity sha512-h1B3A8Z/C7BlnTCHkrWbXZQTViDxfR12lKMeTkT8Sqj5phFmxrBlPE4ORy4lf1Dk5b23mZYE0r/IRACx4ThCrQ== + dependencies: + underscore "1.8.3" + web3-core "1.0.0-beta.37" + web3-core-helpers "1.0.0-beta.37" + web3-core-method "1.0.0-beta.37" + web3-core-promievent "1.0.0-beta.37" + web3-core-subscriptions "1.0.0-beta.37" + web3-eth-abi "1.0.0-beta.37" + web3-utils "1.0.0-beta.37" + +web3-eth-ens@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.0.0-beta.37.tgz#714ecb01eb447ee3eb39b2b20a10ae96edb1f01f" + integrity sha512-dR3UkrVzdRrJhfP57xBPx0CMiVnCcYFvh+u2XMkGydrhHgupSUkjqGr89xry/j1T0BkuN9mikpbyhdCVMXqMbg== + dependencies: + eth-ens-namehash "2.0.8" + underscore "1.8.3" + web3-core "1.0.0-beta.37" + web3-core-helpers "1.0.0-beta.37" + web3-core-promievent "1.0.0-beta.37" + web3-eth-abi "1.0.0-beta.37" + web3-eth-contract "1.0.0-beta.37" + web3-utils "1.0.0-beta.37" + +web3-eth-iban@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.37.tgz#313a3f18ae2ab00ba98678ea1156b09ef32a3655" + integrity sha512-WQRniGJFxH/XCbd7miO6+jnUG+6bvuzfeufPIiOtCbeIC1ypp1kSqER8YVBDrTyinU1xnf1U5v0KBZ2yiWBJxQ== + dependencies: + bn.js "4.11.6" + web3-utils "1.0.0-beta.37" + +web3-eth-personal@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.37.tgz#187472f51861e2b6d45da43411801bc91a859f9a" + integrity sha512-B4dZpGbD+nGnn48i6nJBqrQ+HB7oDmd+Q3wGRKOsHSK5HRWO/KwYeA7wgwamMAElkut50lIsT9EJl4Apfk3G5Q== + dependencies: + web3-core "1.0.0-beta.37" + web3-core-helpers "1.0.0-beta.37" + web3-core-method "1.0.0-beta.37" + web3-net "1.0.0-beta.37" + web3-utils "1.0.0-beta.37" + +web3-eth@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.0.0-beta.37.tgz#0e8ffcd857a5f85ae4b5f052ad831ca5c56f4f74" + integrity sha512-Eb3aGtkz3G9q+Z9DKgSQNbn/u8RtcZQQ0R4sW9hy5KK47GoT6vab5c6DiD3QWzI0BzitHzR5Ji+3VHf/hPUGgw== + dependencies: + underscore "1.8.3" + web3-core "1.0.0-beta.37" + web3-core-helpers "1.0.0-beta.37" + web3-core-method "1.0.0-beta.37" + web3-core-subscriptions "1.0.0-beta.37" + web3-eth-abi "1.0.0-beta.37" + web3-eth-accounts "1.0.0-beta.37" + web3-eth-contract "1.0.0-beta.37" + web3-eth-ens "1.0.0-beta.37" + web3-eth-iban "1.0.0-beta.37" + web3-eth-personal "1.0.0-beta.37" + web3-net "1.0.0-beta.37" + web3-utils "1.0.0-beta.37" + +web3-net@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.0.0-beta.37.tgz#b494136043f3c6ba84fe4a47d4c028c2a63c9a8e" + integrity sha512-xG/uBtMdDa1UMXw9KjDUgf3fXA/fDEJUYUS0TDn+U9PMgngA+UVECHNNvQTrVVDxEky38V3sahwIDiopNsQdsw== + dependencies: + web3-core "1.0.0-beta.37" + web3-core-method "1.0.0-beta.37" + web3-utils "1.0.0-beta.37" + +web3-providers-http@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.0.0-beta.37.tgz#c06efd60e16e329e25bd268d2eefc68d82d13651" + integrity sha512-FM/1YDB1jtZuTo78habFj7S9tNHoqt0UipdyoQV29b8LkGKZV9Vs3is8L24hzuj1j/tbwkcAH+ewIseHwu0DTg== + dependencies: + web3-core-helpers "1.0.0-beta.37" + xhr2-cookies "1.1.0" + +web3-providers-ipc@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.0.0-beta.37.tgz#55d247e7197257ca0c3e4f4b0fe1561311b9d5b9" + integrity sha512-NdRPRxYMIU0C3u18NI8u4bwbhI9pCg5nRgDGYcmSAx5uOBxiYcQy+hb0WkJRRhBoyIXJmy+s26FoH8904+UnPg== + dependencies: + oboe "2.1.3" + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.37" + +web3-providers-ws@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.0.0-beta.37.tgz#77c15aebc00b75d760d22d063ac2e415bdbef72f" + integrity sha512-8p6ZLv+1JYa5Vs8oBn33Nn3VGFBbF+wVfO+b78RJS1Qf1uIOzjFVDk3XwYDD7rlz9G5BKpxhaQw+6EGQ7L02aw== + dependencies: + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.37" + websocket "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible" + +web3-shh@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.0.0-beta.37.tgz#3246ce5229601b525020828a56ee283307057105" + integrity sha512-h5STG/xqZNQWtCLYOu7NiMqwqPea8SfkKQUPUFxXKIPVCFVKpHuQEwW1qcPQRJMLhlQIv17xuoUe1A+RzDNbrw== + dependencies: + web3-core "1.0.0-beta.37" + web3-core-method "1.0.0-beta.37" + web3-core-subscriptions "1.0.0-beta.37" + web3-net "1.0.0-beta.37" + +web3-utils@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.0.0-beta.37.tgz#ab868a90fe5e649337e38bdaf72133fcbf4d414d" + integrity sha512-kA1fyhO8nKgU21wi30oJQ/ssvu+9srMdjOTKbHYbQe4ATPcr5YNwwrxG3Bcpbu1bEwRUVKHCkqi+wTvcAWBdlQ== + dependencies: + bn.js "4.11.6" + eth-lib "0.1.27" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randomhex "0.1.5" + underscore "1.8.3" + utf8 "2.1.1" + +web3@1.0.0-beta.37: + version "1.0.0-beta.37" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.0.0-beta.37.tgz#b42c30e67195f816cd19d048fda872f70eca7083" + integrity sha512-8XLgUspdzicC/xHG82TLrcF/Fxzj2XYNJ1KTYnepOI77bj5rvpsxxwHYBWQ6/JOjk0HkZqoBfnXWgcIHCDhZhQ== + dependencies: + web3-bzz "1.0.0-beta.37" + web3-core "1.0.0-beta.37" + web3-eth "1.0.0-beta.37" + web3-eth-personal "1.0.0-beta.37" + web3-net "1.0.0-beta.37" + web3-shh "1.0.0-beta.37" + web3-utils "1.0.0-beta.37" + +webpack-bundle-analyzer@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.1.0.tgz#2f19cbb87bb6d4f3cb4e59cb67c837bd9436e89d" + integrity sha512-nyDyWEs7C6DZlgvu1pR1zzJfIWSiGPbtaByZr8q+Fd2xp70FuM/8ngCJzj3Er1TYRLSFmp1F1OInbEm4DZH8NA== + dependencies: + acorn "^6.0.7" + acorn-walk "^6.1.1" + bfj "^6.1.1" + chalk "^2.4.1" + commander "^2.18.0" + ejs "^2.6.1" + express "^4.16.3" + filesize "^3.6.1" + gzip-size "^5.0.0" + lodash "^4.17.10" + mkdirp "^0.5.1" + opener "^1.5.1" + ws "^6.0.0" + +webpack-cli@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.0.tgz#55c8a74cae1e88117f9dda3a801c7272e93ca318" + integrity sha512-t1M7G4z5FhHKJ92WRKwZ1rtvi7rHc0NZoZRbSkol0YKl4HvcC8+DsmGDmK7MmZxHSAetHagiOsjOB6MmzC2TUw== + dependencies: + chalk "^2.4.1" + cross-spawn "^6.0.5" + enhanced-resolve "^4.1.0" + findup-sync "^2.0.0" + global-modules "^1.0.0" + import-local "^2.0.0" + interpret "^1.1.0" + loader-utils "^1.1.0" + supports-color "^5.5.0" + v8-compile-cache "^2.0.2" + yargs "^12.0.5" + +webpack-sources@^1.1.0, webpack-sources@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" + integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@^4.29.6: + version "4.29.6" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.29.6.tgz#66bf0ec8beee4d469f8b598d3988ff9d8d90e955" + integrity sha512-MwBwpiE1BQpMDkbnUUaW6K8RFZjljJHArC6tWQJoFm0oQtfoSebtg4Y7/QHnJ/SddtjYLHaKGX64CFjG5rehJw== + dependencies: + "@webassemblyjs/ast" "1.8.5" + "@webassemblyjs/helper-module-context" "1.8.5" + "@webassemblyjs/wasm-edit" "1.8.5" + "@webassemblyjs/wasm-parser" "1.8.5" + acorn "^6.0.5" + acorn-dynamic-import "^4.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chrome-trace-event "^1.0.0" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.0" + json-parse-better-errors "^1.0.2" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + micromatch "^3.1.8" + mkdirp "~0.5.0" + neo-async "^2.5.0" + node-libs-browser "^2.0.0" + schema-utils "^1.0.0" + tapable "^1.1.0" + terser-webpack-plugin "^1.1.0" + watchpack "^1.5.0" + webpack-sources "^1.3.0" + +websocket@^1.0.28: + version "1.0.28" + resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.28.tgz#9e5f6fdc8a3fe01d4422647ef93abdd8d45a78d3" + integrity sha512-00y/20/80P7H4bCYkzuuvvfDvh+dgtXi5kzDf3UcZwN6boTYaKvsrtZ5lIYm1Gsg48siMErd9M4zjSYfYFHTrA== + dependencies: + debug "^2.2.0" + nan "^2.11.0" + typedarray-to-buffer "^3.1.5" + yaeti "^0.0.6" + +"websocket@git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible": + version "1.0.26" + resolved "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" + dependencies: + debug "^2.2.0" + nan "^2.3.3" + typedarray-to-buffer "^3.1.2" + yaeti "^0.0.6" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@^1.2.14, which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +worker-farm@^1.5.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" + integrity sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ== + dependencies: + errno "~0.1.7" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +ws@^3.0.0: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + +ws@^6.0.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" + integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + dependencies: + async-limiter "~1.0.0" + +xhr-request-promise@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.2.tgz#343c44d1ee7726b8648069682d0f840c83b4261d" + integrity sha1-NDxE0e53JrhkgGloLQ+EDIO0Jh0= + dependencies: + xhr-request "^1.0.1" + +xhr-request@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" + integrity sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA== + dependencies: + buffer-to-arraybuffer "^0.0.5" + object-assign "^4.1.1" + query-string "^5.0.1" + simple-get "^2.7.0" + timed-out "^4.0.1" + url-set-query "^1.0.0" + xhr "^2.0.4" + +xhr2-cookies@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" + integrity sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg= + dependencies: + cookiejar "^2.1.1" + +xhr@^2.0.4, xhr@^2.3.3: + version "2.5.0" + resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.5.0.tgz#bed8d1676d5ca36108667692b74b316c496e49dd" + integrity sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ== + dependencies: + global "~4.3.0" + is-function "^1.0.1" + parse-headers "^2.0.0" + xtend "^4.0.0" + +xmlhttprequest@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" + integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw= + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + +"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yaeti@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" + integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc= + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + +yargs-parser@^11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" + integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" + integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ== + dependencies: + camelcase "^4.1.0" + +yargs@^10.0.3: + version "10.1.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5" + integrity sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig== + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^8.1.0" + +yargs@^12.0.5: + version "12.0.5" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" + integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== + dependencies: + cliui "^4.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1" + +yauzl@^2.4.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" diff --git a/script/README.md b/script/README.md new file mode 100644 index 000000000..01c920da1 --- /dev/null +++ b/script/README.md @@ -0,0 +1 @@ +Scripts to make common developer tasks easy to type. diff --git a/script/certora/Dockerfile b/script/certora/Dockerfile new file mode 100644 index 000000000..8e3df4f3d --- /dev/null +++ b/script/certora/Dockerfile @@ -0,0 +1,7 @@ +FROM openjdk:13-alpine + +# Install solc +RUN wget https://github.com/ethereum/solidity/releases/download/v0.5.8/solc-static-linux -O /usr/bin/solc && chmod +x /usr/bin/solc + +# Install bash & z3 +RUN apk add bash z3 diff --git a/script/console b/script/console new file mode 100755 index 000000000..f1d219f42 --- /dev/null +++ b/script/console @@ -0,0 +1,11 @@ +#!/usr/bin/env sh + +DIR=`dirname $0` +PROJ_ROOT="$DIR/.." +export BUILD_DIRECTORY="$PROJ_ROOT/.build-temp" +export NETWORK=${1:-development} +export NETWORK_ID=$(npx truffle exec script/javascript/networkId.js --network "$NETWORK" 3>&2 2>&1 1>&3 3>&-) + +rm -rf $BUILD_DIRECTORY +node "$DIR/javascript/buildTruffle.js" +npx truffle console --network "$NETWORK" diff --git a/script/coverage b/script/coverage new file mode 100755 index 000000000..700b48161 --- /dev/null +++ b/script/coverage @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +dir=`dirname $0` +proj_root="$dir/.." + +[[ ! -d ./.tsbuilt || -z $NO_TSC ]] && "$proj_root/scenario/script/tsc" +case $1 in + "mocha") + export TEST_COMMAND="NETWORK=coverage SCENARIOS="skipall" script/test" + export SKIP_UNITROLLER="" + ;; + "scenario") + export TEST_COMMAND="NETWORK=coverage script/test test/ScenarioTest.js" + export SKIP_UNITROLLER="true" + ;; + *) + ;; +esac + +echo "TEST_COMMAND: $TEST_COMMAND" +echo "SKIP_UNITROLLER: $SKIP_UNITROLLER" + +"$proj_root/node_modules/.bin/solidity-coverage" diff --git a/script/ganache b/script/ganache new file mode 100755 index 000000000..a8b0d2176 --- /dev/null +++ b/script/ganache @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +dir=`dirname $0` +proj_root="$dir/.." + +node "$proj_root/node_modules/ganache-cli/cli.js" \ + --gasLimit 20000000 \ + --gasPrice 20000 \ + --defaultBalanceEther 1000000000 \ + --allowUnlimitedContractSize \ + $@ diff --git a/script/ganache-coverage b/script/ganache-coverage new file mode 100755 index 000000000..c7f109d3f --- /dev/null +++ b/script/ganache-coverage @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +dir=`dirname $0` +proj_root="$dir/.." + +node "$proj_root/node_modules/ethereumjs-testrpc-sc/cli.js" \ + --port 8555 \ + --gasLimit 17592186044415 \ + --gasPrice 1 \ + --allowUnlimitedContractSize \ + $@ diff --git a/script/javascript/buildTruffle.js b/script/javascript/buildTruffle.js new file mode 100644 index 000000000..7bcb21cad --- /dev/null +++ b/script/javascript/buildTruffle.js @@ -0,0 +1,99 @@ +const fs = require('fs'); +const path = require('path'); + +const network = process.env['NETWORK']; +const jsonPath = `networks/${network}.json`; +const contractsPath = `networks/${network}-contracts.json`; +const buildDirectory = process.env['BUILD_DIRECTORY']; +const networkId = process.env['NETWORK_ID']; +let jsonRaw; +let json; + +function error(msg, e=undefined) { + console.error(msg); + if (e) { + console.error(e); + } + + process.exit(1); +} + +if (!buildDirectory) { + error(`required env $BUILD_DIRECTORY not set`); +} + +if (!network) { + error(`required env NETWORK not set`); +} + +function readJson(filePath) { + let json, jsonRaw; + + try { + jsonRaw = fs.readFileSync(filePath, 'utf8'); + } catch (e) { + error(`cannot read \`${filePath}\`, try running \`yarn run deploy\` first`, e) + } + + try { + json = JSON.parse(jsonRaw); + } catch (e) { + error(`cannot parse \`${filePath}\` as JSON. You may delete this file and redeploy.`, e); + } + + return json; +} + +json = readJson(jsonPath); +contracts = readJson(contractsPath); + +const contractTypes = { + PriceOracle: { + singleton: true + }, + Maximillion: { + singleton: true + }, + Comptroller: {}, + Tokens: {} +} + +fs.mkdirSync(path.join(buildDirectory, 'contracts'), { recursive: true }); + +let abis = {}; + +Object.entries(contracts['contracts']).forEach(([key, values]) => { + let [_, contractName] = key.split(':', 2); + + abis[contractName] = values['abi']; +}); + +function addContract(key, contract, address) { + console.info(`${key} (${contract}): ${address}`); + + const json = { + contractName: key, + abi: abis[contract], + networks: { + [networkId]: { + address: address + } + } + }; + + fs.writeFileSync(path.join(buildDirectory, 'contracts', `${key}.json`), JSON.stringify(json)); +} + +Object.entries(contractTypes).forEach(([key, {singleton}]) => { + if (singleton) { + if (json[key] && json[key].address) { + addContract(key, json.contract || key, json[key].address); + } + } else { + Object.entries(json[key]).forEach(([subKey, subJson]) => { + if (subJson.address) { + addContract(subKey, subJson.contract || subKey, subJson.address); + } + }); + } +}); diff --git a/script/javascript/networkId.js b/script/javascript/networkId.js new file mode 100644 index 000000000..aa2a4ed43 --- /dev/null +++ b/script/javascript/networkId.js @@ -0,0 +1,3 @@ +module.exports = function() { + web3.eth.net.getId().then((id) => console.error(id)); +}; \ No newline at end of file diff --git a/script/lint b/script/lint new file mode 100755 index 000000000..c85340a97 --- /dev/null +++ b/script/lint @@ -0,0 +1,8 @@ +#!/usr/bin/env sh +set -e + +DIR=`dirname $0` +PROJ_ROOT="$DIR/.." + +"$PROJ_ROOT/node_modules/.bin/solium" -d "$PROJ_ROOT/test" +"$PROJ_ROOT/node_modules/.bin/solium" -d "$PROJ_ROOT/contracts" diff --git a/script/scen/deploy.scen b/script/scen/deploy.scen new file mode 100755 index 000000000..d9a66a506 --- /dev/null +++ b/script/scen/deploy.scen @@ -0,0 +1,31 @@ +#!/usr/bin/env yarn run repl -s +-- Deploys new Comptroller with some ERC20 and some cTokens + +-- First deploy a price oracle +Gate (PriceOracle Address) (PriceOracle Deploy Simple) + +-- Next a comptroller +Gate (Comptroller Address) (Comptroller Deploy YesNo) + +-- Next an interest rate model +Gate (InterestRateModel InterestRateModel Address) (InterestRateModel Deploy Fixed InterestRateModel 0.0004) + +-- Now deploy some ERC-20 faucet tokens +Gate (Erc20 ZRX Address) (Erc20 Deploy Standard ZRX "0x") +Gate (Erc20 BAT Address) (Erc20 Deploy NonStandard BAT "Basic Attention Token") +Gate (Erc20 DAI Address) (Erc20 Deploy Standard DAI "Dai") +Gate (Erc20 REP Address) (Erc20 Deploy Standard REP "Augur") +Gate (Erc20 USDC Address) (Erc20 Deploy Standard USDC "USD Coin" 6) + +-- Now deploy our cTokens +Gate (CToken cZRX Address) (CToken Deploy CErc20 cZRX "Test 0x 📈" (Erc20 ZRX Address) (Comptroller Address) (InterestRateModel InterestRateModel Address) 0.2e9 8) +Gate (CToken cBAT Address) (CToken Deploy CErc20 cBAT "Test Basic Attention Token 📈" (Erc20 BAT Address) (Comptroller Address) (InterestRateModel InterestRateModel Address) 0.2e9 8) +Gate (CToken cDAI Address) (CToken Deploy CErc20 cDAI "Test Dai 📈" (Erc20 DAI Address) (Comptroller Address) (InterestRateModel InterestRateModel Address) 0.2e9 8) +Gate (CToken cREP Address) (CToken Deploy CErc20 cREP "Test Augur 📈" (Erc20 REP Address) (Comptroller Address) (InterestRateModel InterestRateModel Address) 0.2e9 8) +Gate (CToken cETH Address) (CToken Deploy CEther cETH "Test Ether 📈" (Comptroller Address) (InterestRateModel InterestRateModel Address) 0.2e9 8) +Gate (CToken cUSDC Address) (CToken Deploy CErc20 cUSDC "Test USD Coin 📈" (Erc20 USDC Address) (Comptroller Address) (InterestRateModel InterestRateModel Address) 2e-4 8) + +-- Deploy Maximillion +Gate (Maximillion Address) (Maximillion Deploy cETH) + +Print "Deployed Comptroller and cTokens: cETH, cBAT, cDAI, cREP, cUSDC and cZRX" diff --git a/script/scenario b/script/scenario new file mode 100755 index 000000000..e9b2a915b --- /dev/null +++ b/script/scenario @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +dir=`dirname $0` +proj_root="$dir/.." +verbose=${verbose:-} + +# Combine any params as simple regex (a|b|c) +IFS='|' +verbose="$verbose" SCENARIOS="$*" "$dir/test" "test/ScenarioTest.js" diff --git a/script/test b/script/test new file mode 100755 index 000000000..be995d2c1 --- /dev/null +++ b/script/test @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +dir=`dirname $0` +proj_root="$dir/.." +test_root="$dir/../test" +contracts_root="$dir/../contracts" +network=${NETWORK:-test} +verbose=${verbose:-} + +function cleanup { + mv "$contracts_root/test" "$test_root/contracts" +} + +trap cleanup EXIT + +mv "$test_root/contracts" "$contracts_root/test" + +if [ "$CI" -a ! "$1" ]; then + set -x + set -- "$@" $(circleci tests glob "test/**/*Test.js" "test/**/*Test.sol" | circleci tests split --split-by=timings) +fi + +# Coverage clones our project but not node_modules, so let's hop +# up one directory. +if [ ! -d "$proj_root/node_modules" -a -d "$proj_root/../node_modules" ]; then + proj_root="$proj_root/.." +fi + +# Compile scenario runner +[[ ! -d ./.tsbuilt || -z $NO_TSC ]] && "$proj_root/scenario/script/tsc" +[[ -z $no_compile ]] && solc --combined-json bin,abi --optimize contracts/*.sol contracts/**/*.sol --allow-paths ./contracts,./contracts/test > $proj_root/networks/${network}-contracts.json + +echo "cwd: $(pwd), proj_root: $(cd $proj_root && pwd), networks: $(ls -l $proj_root/networks/${network}-contracts.json)" +node --stack_size=10000 "$proj_root/node_modules/truffle/build/cli.bundled.js" compile --network "$network" +proj_root="$proj_root" verbose="$verbose" node --stack_size=10000 "$proj_root/node_modules/truffle/build/cli.bundled.js" test --network "$network" $@ diff --git a/script/verify b/script/verify new file mode 100755 index 000000000..03acc503e --- /dev/null +++ b/script/verify @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +set -eo + +dir=`dirname $0` +proj_root="$dir/.." +contracts="`(cd $proj_root && pwd)`/contracts" +emv_jar="$proj_root/scripts/certora/emv.jar" + +command -v java >/dev/null 2>&1 || { echo "Error: java is not installed." >&2; exit 1; } +command -v z3 >/dev/null 2>&1 || { echo "Error: z3 is not installed." >&2; exit 1; } + +function verify_spec { + [ -e "$1" ] || (echo "spec file not found: $1" && exit 1) + + set -x + java -jar "$emv_jar" -spec "$1" -theory INT -s z3 -graphDrawLimit 0 -path $contracts + set +x +} + +if [ "$CI" ]; then + all_specs=($(circleci tests glob "$proj_root/spec/formal/*.spclnk" | circleci tests split --split-by=timings)) + echo XXX disabled in CI for now... && exit 0 +else + if [[ $# -eq 0 ]] ; then + all_specs=($proj_root/spec/formal/*.spclnk) + else + all_specs=($@) + fi +fi + +echo "running specs ${all_specs[@]}" + +for spec in "${all_specs[@]}"; do + verify_spec "$spec" +done diff --git a/spec/formal/CompoundIgnoreExtCalls.spclnk b/spec/formal/CompoundIgnoreExtCalls.spclnk new file mode 100644 index 000000000..98c102acb --- /dev/null +++ b/spec/formal/CompoundIgnoreExtCalls.spclnk @@ -0,0 +1,13 @@ +{ + "contracts": [ + { + "name": "CErc20Certora", + "file": "spec/formal/contracts/CErc20Certora.sol", + "address": "123" + } + ], + + "cvlsToCheck": { + "CErc20Certora": ["spec/formal/general.cvl"] + } +} \ No newline at end of file diff --git a/spec/formal/EIP20.spclnk b/spec/formal/EIP20.spclnk new file mode 100644 index 000000000..cb89e5607 --- /dev/null +++ b/spec/formal/EIP20.spclnk @@ -0,0 +1,145 @@ +{ + "contracts": [ + { + "name": "ComptrollerModel", + "file": "spec/formal/contracts/ComptrollerModel.sol", + "address": "789", + "methods": [ + { + "name": "mintAllowed", + "args": ["address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "mintVerify", + "args": ["address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "redeemAllowed", + "args": ["address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "redeemVerify", + "args": ["address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "borrowAllowed", + "args": ["address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "borrowVerify", + "args": ["address","address","uint256"], + "returns": [] + }, + { + "name": "repayBorrowAllowed", + "args": ["address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "repayBorrowVerify", + "args": ["address","address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "liquidateBorrowAllowed", + "args": ["address","address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "liquidateBorrowVerify", + "args": ["address","address","address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "seizeAllowed", + "args": ["address","address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "seizeVerify", + "args": ["address","address","address","address","uint256"], + "returns": [] + }, + { + "name": "transferAllowed", + "args": ["address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "transferVerify", + "args": ["address","address","address","uint256"], + "returns": [] + }, + { + "name": "liquidateCalculateSeizeTokens", + "args": ["address","address","uint256"], + "returns": ["uint256","uint256"] + } + ] + }, + + { + "name": "UnderlyingModelNonStandard", + "file": "spec/formal/contracts/UnderlyingModelNonStandard.sol", + "address": "456", + "methods": [ + { + "name": "balanceOf", + "args": ["address"], + "returns": ["uint256"] + }, + { + "name": "allowance", + "args": ["address","address"], + "returns": ["uint256"] + }, + { + "name": "totalSupply", + "args": [], + "returns": ["uint256"] + }, + { + "name": "transfer", + "args": ["address","uint256"], + "returns": [] + }, + { + "name": "transferFrom", + "args": ["address","address","uint256"], + "returns": [] + }, + { + "name": "approve", + "args": ["address","uint256"], + "returns": ["bool"] + }, + { + "name": "dummy", + "args": [], + "returns": [] + } + ] + }, + + { + "name": "CErc20Certora", + "file": "spec/formal/contracts/CErc20Certora.sol", + "address": "123", + "state": { + 6: "789", + 18: "456" + } + } + ], + + "cvlsToCheck": { + "CErc20Certora": [ + "spec/formal/eip20.cvl" + ] + } +} \ No newline at end of file diff --git a/spec/formal/Liquidate.spclnk b/spec/formal/Liquidate.spclnk new file mode 100644 index 000000000..ee73e4aea --- /dev/null +++ b/spec/formal/Liquidate.spclnk @@ -0,0 +1,208 @@ +{ + "contracts": [ + { + "name": "ComptrollerModel", + "file": "spec/formal/contracts/ComptrollerModel.sol", + "address": "789", + "methods": [ + { + "name": "mintAllowed", + "args": ["address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "mintVerify", + "args": ["address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "redeemAllowed", + "args": ["address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "redeemVerify", + "args": ["address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "borrowAllowed", + "args": ["address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "borrowVerify", + "args": ["address","address","uint256"], + "returns": [] + }, + { + "name": "repayBorrowAllowed", + "args": ["address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "repayBorrowVerify", + "args": ["address","address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "liquidateBorrowAllowed", + "args": ["address","address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "liquidateBorrowVerify", + "args": ["address","address","address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "seizeAllowed", + "args": ["address","address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "seizeVerify", + "args": ["address","address","address","address","uint256"], + "returns": [] + }, + { + "name": "transferAllowed", + "args": ["address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "transferVerify", + "args": ["address","address","address","uint256"], + "returns": [] + }, + { + "name": "liquidateCalculateSeizeTokens", + "args": ["address","address","uint256"], + "returns": ["uint256","uint256"] + } + ] + }, + + { + "name": "UnderlyingModelNonStandard", + "file": "spec/formal/contracts/UnderlyingModelNonStandard.sol", + "address": "456", + "methods": [ + { + "name": "balanceOf", + "args": ["address"], + "returns": ["uint256"] + }, + { + "name": "allowance", + "args": ["address","address"], + "returns": ["uint256"] + }, + { + "name": "totalSupply", + "args": [], + "returns": ["uint256"] + }, + { + "name": "transfer", + "args": ["address","uint256"], + "returns": [] + }, + { + "name": "transferFrom", + "args": ["address","address","uint256"], + "returns": [] + }, + { + "name": "approve", + "args": ["address","uint256"], + "returns": ["bool"] + }, + { + "name": "dummy", + "args": [], + "returns": [] + } + ] + }, + + { + "name": "CTokenCollateral", + "file": "spec/formal/contracts/CTokenCollateral.sol", + "address": "321", + "state": { + 6: "789", + 18: "456" + }, + "methods": [ + { + "name": "accrualBlockNumber", + "args": [], + "returns": ["uint256"] + }, + { + "name": "balanceOf", + "args": ["address"], + "returns": ["uint256"] + }, + { + "name": "borrowBalanceStored", + "args": ["address"], + "returns": ["uint256"] + }, + { + "name": "exchangeRateStored", + "args": [], + "returns": ["uint256"] + }, + { + "name": "getCash", + "args": [], + "returns": ["uint256"] + }, + { + "name": "getCashOf", + "args": ["address"], + "returns": ["uint256"] + }, + { + "name": "totalSupply", + "args": [], + "returns": ["uint256"] + }, + { + "name": "totalBorrows", + "args": [], + "returns": ["uint256"] + }, + { + "name": "totalReserves", + "args": [], + "returns": ["uint256"] + }, + { + "name": "seize", + "args": ["address,address,uint256"], + "returns": ["uint256"] + } + ] + }, + + { + "name": "CErc20Certora", + "file": "spec/formal/contracts/CErc20Certora.sol", + "address": "123", + "state": { + 6: "789", + 18: "456", + 19: "321" + } + } + ], + + "cvlsToCheck": { + "CErc20Certora": [ + "spec/formal/liquidateFresh.cvl" + ] + } +} \ No newline at end of file diff --git a/spec/formal/Maximillion.spclnk b/spec/formal/Maximillion.spclnk new file mode 100644 index 000000000..88c1213f1 --- /dev/null +++ b/spec/formal/Maximillion.spclnk @@ -0,0 +1,127 @@ +{ + "contracts": [ + { + "name": "ComptrollerModel", + "file": "spec/formal/contracts/ComptrollerModel.sol", + "address": "789", + "methods": [ + { + "name": "mintAllowed", + "args": ["address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "mintVerify", + "args": ["address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "redeemAllowed", + "args": ["address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "redeemVerify", + "args": ["address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "borrowAllowed", + "args": ["address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "borrowVerify", + "args": ["address","address","uint256"], + "returns": [] + }, + { + "name": "repayBorrowAllowed", + "args": ["address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "repayBorrowVerify", + "args": ["address","address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "liquidateBorrowAllowed", + "args": ["address","address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "liquidateBorrowVerify", + "args": ["address","address","address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "seizeAllowed", + "args": ["address","address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "seizeVerify", + "args": ["address","address","address","address","uint256"], + "returns": [] + }, + { + "name": "transferAllowed", + "args": ["address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "transferVerify", + "args": ["address","address","address","uint256"], + "returns": [] + }, + { + "name": "liquidateCalculateSeizeTokens", + "args": ["address","address","uint256"], + "returns": ["uint256","uint256"] + } + ] + }, + + { + "name": "CEtherCertora", + "file": "spec/formal/contracts/CEtherCertora.sol", + "address": "234", + "state": { + 6: "789" + }, + "methods": [ + { + "name": "borrowBalanceCurrent", + "args": ["address"], + "returns": ["uint256"] + }, + { + "name": "repayBorrowBehalf", + "args": ["address"], + "returns": [] + }, + { + "name": "totalBorrows", + "args": [], + "returns": ["uint256"] + } + ] + }, + + { + "name": "MaximillionCertora", + "file": "spec/formal/contracts/MaximillionCertora.sol", + "address": "666", + "state": { + 0: "234" + } + } + ], + + "cvlsToCheck": { + "MaximillionCertora": [ + "spec/formal/maximillion.cvl" + ] + } +} \ No newline at end of file diff --git a/spec/formal/MintRedeemBorrowRepay.spclnk b/spec/formal/MintRedeemBorrowRepay.spclnk new file mode 100644 index 000000000..ca6350e7a --- /dev/null +++ b/spec/formal/MintRedeemBorrowRepay.spclnk @@ -0,0 +1,209 @@ +{ + "contracts": [ + { + "name": "ComptrollerModel", + "file": "spec/formal/contracts/ComptrollerModel.sol", + "address": "789", + "methods": [ + { + "name": "mintAllowed", + "args": ["address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "mintVerify", + "args": ["address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "redeemAllowed", + "args": ["address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "redeemVerify", + "args": ["address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "borrowAllowed", + "args": ["address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "borrowVerify", + "args": ["address","address","uint256"], + "returns": [] + }, + { + "name": "repayBorrowAllowed", + "args": ["address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "repayBorrowVerify", + "args": ["address","address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "liquidateBorrowAllowed", + "args": ["address","address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "liquidateBorrowVerify", + "args": ["address","address","address","address","uint256","uint256"], + "returns": [] + }, + { + "name": "seizeAllowed", + "args": ["address","address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "seizeVerify", + "args": ["address","address","address","address","uint256"], + "returns": [] + }, + { + "name": "transferAllowed", + "args": ["address","address","address","uint256"], + "returns": ["uint256"] + }, + { + "name": "transferVerify", + "args": ["address","address","address","uint256"], + "returns": [] + }, + { + "name": "liquidateCalculateSeizeTokens", + "args": ["address","address","uint256"], + "returns": ["uint256","uint256"] + } + ] + }, + + { + "name": "UnderlyingModelNonStandard", + "file": "spec/formal/contracts/UnderlyingModelNonStandard.sol", + "address": "456", + "methods": [ + { + "name": "balanceOf", + "args": ["address"], + "returns": ["uint256"] + }, + { + "name": "allowance", + "args": ["address","address"], + "returns": ["uint256"] + }, + { + "name": "totalSupply", + "args": [], + "returns": ["uint256"] + }, + { + "name": "transfer", + "args": ["address","uint256"], + "returns": [] + }, + { + "name": "transferFrom", + "args": ["address","address","uint256"], + "returns": [] + }, + { + "name": "approve", + "args": ["address","uint256"], + "returns": ["bool"] + }, + { + "name": "dummy", + "args": [], + "returns": [] + } + ] + }, + + { + "name": "CTokenCollateral", + "file": "spec/formal/contracts/CTokenCollateral.sol", + "address": "321", + "state": { + 6: "789", + 18: "456" + }, + "methods": [ + { + "name": "accrualBlockNumber", + "args": [], + "returns": ["uint256"] + }, + { + "name": "balanceOf", + "args": ["address"], + "returns": ["uint256"] + }, + { + "name": "borrowBalanceStored", + "args": ["address"], + "returns": ["uint256"] + }, + { + "name": "exchangeRateStored", + "args": [], + "returns": ["uint256"] + }, + { + "name": "getCash", + "args": [], + "returns": ["uint256"] + }, + { + "name": "getCashOf", + "args": ["address"], + "returns": ["uint256"] + }, + { + "name": "totalSupply", + "args": [], + "returns": ["uint256"] + }, + { + "name": "totalBorrows", + "args": [], + "returns": ["uint256"] + }, + { + "name": "totalReserves", + "args": [], + "returns": ["uint256"] + }, + { + "name": "seize", + "args": ["address,address,uint256"], + "returns": ["uint256"] + } + ] + }, + + { + "name": "CErc20Certora", + "file": "spec/formal/contracts/CErc20Certora.sol", + "address": "123", + "state": { + 6: "789", + 18: "456", + 19: "321" + } + } + ], + + "cvlsToCheck": { + "CErc20Certora": [ + "spec/formal/mintAndRedeemFresh.cvl", + "spec/formal/borrowAndRepayFresh.cvl" + ] + } +} \ No newline at end of file diff --git a/spec/formal/_setMarketPolicyHook.cvl b/spec/formal/_setMarketPolicyHook.cvl new file mode 100644 index 000000000..f109b36a4 --- /dev/null +++ b/spec/formal/_setMarketPolicyHook.cvl @@ -0,0 +1,72 @@ +methods { + admin() returns address + _setMarketPolicyHook(address,address) returns uint256 + markets(address) returns bool,uint256,uint256,address,address,uint256,uint256,uint256,uint256,uint256,uint256 +} + +_setMarketPolicyHook(uint result, uint currentAdmin, address asset, address currentPolicyHook, address reqPolicyHook,address newPolicyHook, bool isListed) +description "Failed to set market policy hook from $currentPolicyHook to $reqPolicyHook for $asset (result=$result, admin=$currentAdmin, newPolicyHook=newPolicyHook, isListed=$isListed)" { + // N.B. The implementation calls `policyHook.isPolicyHook()` + // which needs to return true for the call to _setMarketPolicyHook to succeed. + // We can't currently control or specify that, so we may get intermittent failures. + + bool isListedT; + address currentPolicyHookT; + address newPolicyHookT; + + // Free Variables + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + // Strict ordering + static_require e1.block > e0.block; + static_require e2.block > e1.block; + + // Capture current admin and collateral factor + static_require currentAdmin == sinvoke admin(e0); + + isListedT, _, _, _, currentPolicyHookT, _, _, _, _, _, _ = sinvoke markets(e0, asset); + + static_require isListed == isListedT; + static_require currentPolicyHook == currentPolicyHookT; + + // Invoke set collateral factor + uint256 resultT = sinvoke _setMarketPolicyHook(e1, asset, reqPolicyHook); + + static_require result == resultT; + + _, _, _, _, newPolicyHookT, _, _, _, _, _, _ = sinvoke markets(e2, asset); + + static_require newPolicyHook == newPolicyHookT; + + static_assert ( + ( + // success + result == 0 && + e1.msg.sender == currentAdmin && + newPolicyHook == reqPolicyHook && + isListed + ) || + ( + // fail unauthorized + result == 1 && + e1.msg.sender != currentAdmin && + newPolicyHook == currentPolicyHook + ) || + ( + // fail not listed + result == 10 && + e1.msg.sender == currentAdmin && + newPolicyHook == currentPolicyHook && + !isListed + ) || + ( + // fail bad input + result == 5 && + e1.msg.sender == currentAdmin && + newPolicyHook == currentPolicyHook && + isListed + ) + ); +} \ No newline at end of file diff --git a/spec/formal/_setMarketPriceOracle.cvl b/spec/formal/_setMarketPriceOracle.cvl new file mode 100644 index 000000000..60d0675aa --- /dev/null +++ b/spec/formal/_setMarketPriceOracle.cvl @@ -0,0 +1,63 @@ +methods { + admin() returns address + markets(address) returns bool,uint256,uint256,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256 + _setMarketPriceOracle(address,address) returns uint256 +} + +_setMarketPriceOracle(uint result, address asset, address reqPriceOracle) +description "Failed to set market oracle for $asset with result $result (result=$result, asset=$asset, reqPriceOracle=$reqPriceOracle)" { + // N.B. The implementation calls `priceOracle.assetPrices(address(0))` + // which needs to not revert for the call to succeed. + + address currAdmin; + bool currListed; + address currPriceOracle; + address nextPriceOracle; + + // Free Variables + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + // Strict ordering + static_require e1.block > e0.block; + static_require e2.block > e1.block; + + // Capture curr values + uint currAdmin = sinvoke admin(e0); + currListed, _, _, currPriceOracle, _, _, _, _, _, _, _, _ = sinvoke markets(e0, asset); + + // Invoke set market oracle + uint256 resultT = sinvoke _setMarketPriceOracle(e1, asset, reqPriceOracle); + static_require result == resultT; + + // Get next value + _, _, _, nextPriceOracle, _, _, _, _, _, _, _, _ = sinvoke markets(e2, asset); + + // Guarantee return values + static_assert( + result == 0 || + result == 1 || + result == 10 + ); + + // Success case updates market + static_assert(result == 0 <=> ( + e1.msg.sender == currAdmin && + nextPriceOracle == reqPriceOracle && + currListed + )); + + // Unauthorized case + static_assert(result == 1 <=> ( + e1.msg.sender != currAdmin && + nextPriceOracle == currPriceOracle + )); + + // Unlisted case + static_assert(result == 10 <=> ( + e1.msg.sender == currAdmin && + nextPriceOracle == currPriceOracle && + !currListed + )); +} \ No newline at end of file diff --git a/spec/formal/accrueInterest.cvl b/spec/formal/accrueInterest.cvl new file mode 100644 index 000000000..184e0fb1a --- /dev/null +++ b/spec/formal/accrueInterest.cvl @@ -0,0 +1,77 @@ +methods { + getCash() returns uint256 + accrueInterest() returns uint256 + interestRateModelGetBorrowRate() returns uint256, uint256 + accrualBlockNumber() returns uint256 + borrowIndex() returns uint256 + totalBorrows() returns uint256 + totalReserves() returns uint256 + reserveFactorMantissa() returns uint256 +} + +accrueInterest(uint result) +description "Break accrueInterest with result=$result, block delta is $delta" { + // Pre/action/post environments + env e0; havoc e0; // pre+action + env e1; havoc e1; // post + + static_require e1.block.number >= e0.block.number; + + // fetch pre + uint256 cTokenCashPre = sinvoke getCash(e0); + uint256 interestRateModelErr; + uint256 borrowRateMantissaPre; + interestRateModelErr, borrowRateMantissaPre = sinvoke interestRateModelGetBorrowRate(e0); + uint256 accrualBlockNumberPre = sinvoke accrualBlockNumber(e0); + uint256 borrowIndexPre = sinvoke borrowIndex(e0); + uint256 totalBorrowsPre = sinvoke totalBorrows(e0); + uint256 totalReservesPre = sinvoke totalReserves(e0); + uint256 reserveFactorPre = sinvoke reserveFactorMantissa(e0); + + // internal computations + uint256 delta = e0.block.number-accrualBlockNumberPre; + uint256 simpleInterestFactor = delta*borrowRateMantissaPre; + uint256 interestAccumulated = (totalBorrowsPre * simpleInterestFactor) / 1000000000000000000; // div 1000000000000000000 + + // post expected + uint256 borrowIndexPostExpected = borrowIndexPre + (borrowIndexPre*simpleInterestFactor)/1000000000000000000; // div 1000000000000000000 the right multiplicand + uint256 totalBorrowsPostExpected = totalBorrowsPre + interestAccumulated; + uint256 totalReservesPostExpected = totalReservesPre + (interestAccumulated*reserveFactorPre)/1000000000000000000; // div 1000000000000000000 the right multiplicand + + // Action! + static_require result == invoke accrueInterest(e0); + bool accrueInterestReverted = lastReverted; + + // fetch post + uint256 accrualBlockNumberPost = sinvoke accrualBlockNumber(e1); + uint256 borrowIndexPostActual = sinvoke borrowIndex(e1); + uint256 totalBorrowsPostActual = sinvoke totalBorrows(e1); + uint256 totalReservesPostActual = sinvoke totalReserves(e1); + + uint256 NO_ERROR = 0; + uint256 INTEREST_RATE_MODEL_ERROR = 5; + uint256 MATH_ERROR = 9; + + // Guarantee return values + static_assert (!accrueInterestReverted) => + (result == NO_ERROR || + result == INTEREST_RATE_MODEL_ERROR || + result == MATH_ERROR), "Got unexpected error code $result"; + + static_assert (!accrueInterestReverted => (result == INTEREST_RATE_MODEL_ERROR <=> interestRateModelErr != 0)), "Mismatch in case of interest rate model error"; + + static_assert (!accrueInterestReverted => + ((result != 0 || delta == 0) <=> + (accrualBlockNumberPost == accrualBlockNumberPre && + borrowIndexPostActual == borrowIndexPre && + totalBorrowsPostActual == totalBorrowsPre && + totalReservesPostActual == totalReservesPre))), "Mismatch in error case"; + + static_assert (!accrueInterestReverted => + ((result == 0 /*&& delta > 0*/) <=> + (accrualBlockNumberPost == e0.block.number && + borrowIndexPostActual == borrowIndexPostExpected && + totalBorrowsPostActual == totalBorrowsPostExpected && + totalReservesPostActual == totalReservesPostExpected + ))), "Mismatch in no error case: borrowIndex: pre=$borrowIndexPre, actual=$borrowIndexPostActual, expected=$borrowIndexPostExpected; totalBorrows: pre=$totalBorrowsPre, actual=$totalBorrowsPostActual, expected=$totalBorrowsPostExpected; totalReserves: pre=$totalReservesPre, acutal=$totalReservesPostActual, expected=$totalReservesPostExpected"; +} diff --git a/spec/formal/admin_setCollateralFactor.cvl b/spec/formal/admin_setCollateralFactor.cvl new file mode 100644 index 000000000..b6695f5b2 --- /dev/null +++ b/spec/formal/admin_setCollateralFactor.cvl @@ -0,0 +1,101 @@ +methods { +// taken from solc --hashes contracts/MoneyMarket.sol +/*e4028eee: */ _setCollateralFactor(address,uint256) returns uint256 +/*f851a440: */ admin() returns address +/*3b8a7478: */ getCollateralFactorREMOVE_ME(address) returns uint256 +/*e43fb3a9: */ getMarketListedREMOVE_ME(address) returns bool +/*8e8f294b: */ markets(address) // TODO: returns market tuple +/*7dc0d1d0: */ oracle() returns address +} + +_setCollateralFactor(uint currentAdmin, address asset, uint currentCollateralFactor, uint newCollateralFactor) +description "Failed to set collateralFactor from $currentCollateralFactor to $newCollateralFactor for $asset (admin=$currentAdmin)" { + // N.B. For non-zero collateralFactor, the implementation calls `oracleInterface.assetPrices(address($asset))` + // which needs to return non-zero for the call to _setCollateralFactor to succeed. + // We can't currently control or specify that, so we may get intermittent failures. + + // Free Variables + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + // Strict ordering + static_require e1.block > e0.block; + static_require e2.block > e1.block; + + // Capture current admin and collateral factor + static_require currentAdmin == sinvoke admin(e0); + // getCollateralFactorREMOVE_ME is a workaround until we have support for structs + static_require currentCollateralFactor == sinvoke getCollateralFactorREMOVE_ME(e0, asset); + + // Invoke set collateral factor + uint256 result = sinvoke _setCollateralFactor(e1, asset, newCollateralFactor); + + // collateralFactor changes <=> msg.sender == currentAdmin + + // newCollateralFactor > 0 && oracle non-zero & price > 0 + // newCollateralFactor == 0 + + static_assert ( + ( + // fail is caller is not admin + e1.msg.sender != currentAdmin && + result != 0 && + // getCollateralFactorREMOVE_ME is a workaround until we have support for structs + sinvoke getCollateralFactorREMOVE_ME(e2, asset) == currentCollateralFactor + ) + || + ( + // fail if not listed + e1.msg.sender == currentAdmin && + sinvoke getMarketListedREMOVE_ME(e2, asset) != true && + result == 9 && // MARKET_NOT_LISTED + sinvoke getCollateralFactorREMOVE_ME(e2, asset) == currentCollateralFactor + ) + || + ( + // fail if listed but newCollateralFactor too high + e1.msg.sender == currentAdmin && + sinvoke getMarketListedREMOVE_ME(e2, asset) && + // 0.9 * 1e18: 9e17 + newCollateralFactor > 900000000000000000 && + result == 25 && // INVALID_COLLATERAL_FACTOR + sinvoke getCollateralFactorREMOVE_ME(e2, asset) == currentCollateralFactor + ) + || + ( + // Succeed if sender is admin, market listed, newCollateralFactor > 0 and oracle set + // In this case we also require oracleInterface.assetPrices(asset) > 0, but we can't currently specify that + // as it involves a call to another contract. + e1.msg.sender == currentAdmin && + sinvoke getMarketListedREMOVE_ME(e2, asset) && + // 0.9 * 1e18: 9e17 + newCollateralFactor > 0 && + newCollateralFactor <= 900000000000000000 && + sinvoke oracle(e2) > 0 && + result == 0 && + sinvoke getCollateralFactorREMOVE_ME(e2, asset) == newCollateralFactor + ) + || + ( + // Succeed if sender is admin, market listed, newCollateralFactor == 0 + e1.msg.sender == currentAdmin && + sinvoke getMarketListedREMOVE_ME(e2, asset) && + newCollateralFactor == 0 && + result == 0 && + sinvoke getCollateralFactorREMOVE_ME(e2, asset) == newCollateralFactor + ) + || + ( + // fail if listed and newCollateralFactor > 0 but not too high but no oracle has been set + e1.msg.sender == currentAdmin && + sinvoke getMarketListedREMOVE_ME(e2, asset) && + // 0.9 * 1e18: 9e17 + newCollateralFactor > 0 && + newCollateralFactor <= 900000000000000000 && + sinvoke oracle(e2) == 0 && + result == 23 && // ZERO_ORACLE_ADDRESS + sinvoke getCollateralFactorREMOVE_ME(e2, asset) == currentCollateralFactor + ) + ); +} \ No newline at end of file diff --git a/spec/formal/borrowAndRepayFresh.cvl b/spec/formal/borrowAndRepayFresh.cvl new file mode 100644 index 000000000..bf48f8106 --- /dev/null +++ b/spec/formal/borrowAndRepayFresh.cvl @@ -0,0 +1,257 @@ +methods { + totalSupply() returns uint256 + totalBorrows() returns uint256 + totalReserves() returns uint256 + + balanceOf(address) returns uint256 + borrowBalanceStored(address) returns uint256 + exchangeRateStored() returns uint256 + + getCash() returns uint256 + getCashOf(address) returns uint256 // not part of API + + borrowFreshPub(address, uint256) returns uint256 + repayBorrowFreshPub(address, address, uint256) returns uint256 + + checkTransferInPub(address,uint256) returns uint256 + doTransferInPubSim(address,uint256) returns uint256 +} + +borrowFresh(uint result, address borrower, uint256 borrowAmount) +description "Break borrow with result=$result borrower=$borrower borrowAmount=$borrowAmount" { + // Pre/action/post environments + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + // Any other account + address other; havoc other; + static_require other != borrower && other != currentContract; + + /* + - exchange rate should not change + - errors should have no effect + - no *other* storage should change - XXX can we specify this? + + |----------+--------+----------+-------| + | | CToken | Borrower | Other | + |----------+--------+----------+-------| + | cash | -A | +A | 0 | + | borrows | +A | +A | 0 | + | tokens | 0 | 0 | 0 | + | reserves | 0 | | | + |----------+--------+----------+-------| + */ + + /* Pre */ + + uint256 exchangeRatePre = sinvoke exchangeRateStored(e0); + + uint256 cTokenCashPre = sinvoke getCash(e0); + uint256 borrowerCashPre = sinvoke getCashOf(e0, borrower); + uint256 otherCashPre = sinvoke getCashOf(e0, other); + + uint256 cTokenBorrowsPre = sinvoke totalBorrows(e0); + uint256 borrowerBorrowsPre = sinvoke borrowBalanceStored(e0, borrower); + uint256 otherBorrowsPre = sinvoke borrowBalanceStored(e0, other); + + uint256 cTokenTokensPre = sinvoke totalSupply(e0); + uint256 borrowerTokensPre = sinvoke balanceOf(e0, borrower); + uint256 otherTokensPre = sinvoke balanceOf(e0, other); + + uint256 cTokenReservesPre = sinvoke totalReserves(e0); + + // Just Do It + static_require result == invoke borrowFreshPub(e1, borrower, borrowAmount); + bool borrowFreshReverted = lastReverted; + + /* Post */ + + uint256 exchangeRatePost = sinvoke exchangeRateStored(e2); + + uint256 cTokenCashPost = sinvoke getCash(e2); + uint256 borrowerCashPost = sinvoke getCashOf(e2, borrower); + uint256 otherCashPost = sinvoke getCashOf(e2, other); + + uint256 cTokenBorrowsPost = sinvoke totalBorrows(e2); + uint256 borrowerBorrowsPost = sinvoke borrowBalanceStored(e2, borrower); + uint256 otherBorrowsPost = sinvoke borrowBalanceStored(e2, other); + + uint256 cTokenTokensPost = sinvoke totalSupply(e2); + uint256 borrowerTokensPost = sinvoke balanceOf(e2, borrower); + uint256 otherTokensPost = sinvoke balanceOf(e2, other); + + uint256 cTokenReservesPost = sinvoke totalReserves(e2); + + // Measure + bool staticBalance = + (exchangeRatePost == exchangeRatePre) && + (cTokenCashPost == cTokenCashPre) && + (cTokenBorrowsPost == cTokenBorrowsPre) && + (cTokenTokensPost == cTokenTokensPre) && + (cTokenReservesPost == cTokenReservesPre) && + (borrowerCashPost == borrowerCashPre) && + (borrowerBorrowsPost == borrowerBorrowsPre) && + (borrowerTokensPost == borrowerTokensPre) && + (otherCashPost == otherCashPre) && + (otherBorrowsPost == otherBorrowsPre) && + (otherTokensPost == otherTokensPre); + + bool dynamicBalance = + (borrowAmount != 0) && + (exchangeRatePost == exchangeRatePre) && + (cTokenCashPost == cTokenCashPre - borrowAmount) && + (cTokenBorrowsPost == cTokenBorrowsPre + borrowAmount) && + (cTokenTokensPost == cTokenTokensPre) && + (cTokenReservesPost == cTokenReservesPre) && + (borrowerCashPost == borrowerCashPre + borrowAmount) && + (borrowerBorrowsPost == borrowerBorrowsPre + borrowAmount) && + (borrowerTokensPost == borrowerTokensPre) && + (otherCashPost == otherCashPre) && + (otherBorrowsPost == otherBorrowsPre) && + (otherTokensPost == otherTokensPre); + + // XXX would be nice to pull named enums from actual contract? + static_assert (!borrowFreshReverted => + ((result != 0 || borrowAmount == 0) <=> staticBalance)), "Mismatch in static case"; + static_assert (!borrowFreshReverted => + ((result == 0 && borrowAmount != 0 && borrower != currentContract) <=> dynamicBalance)), "Mismatch in dynamic case"; +} + +repayBorrowFresh(uint result, address payer, address borrower, uint256 repayAmount) +description "Break repay borrow with realRepayAmount=$realRepayAmount borrowerBorrowsPre=$borrowerBorrowsPre" { + // Pre/action/post environments + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + // Any other account + address other; havoc other; + static_require other != payer && other != borrower && other != currentContract; + + // We assume this cannot happen + // OQ: should we enforce in the code such that it need not be assumed? + static_require borrower != currentContract; + + /* + |----------+--------+-------+----------+-------| + | | CToken | Payer | Borrower | Other | + |----------+--------+-------+----------+-------| + | cash | +A | -A | -A/0 | 0 | + | borrows | -A | -A/0 | -A | 0 | + | tokens | 0 | 0 | 0 | 0 | + | reserves | 0 | | | | + |----------+--------+-------+----------+-------| + */ + + /* Pre */ + + uint256 exchangeRatePre = sinvoke exchangeRateStored(e0); + + uint256 cTokenCashPre = sinvoke getCash(e0); + uint256 payerCashPre = sinvoke getCashOf(e0, payer); + uint256 borrowerCashPre = sinvoke getCashOf(e0, borrower); + uint256 otherCashPre = sinvoke getCashOf(e0, other); + + uint256 cTokenBorrowsPre = sinvoke totalBorrows(e0); + uint256 payerBorrowsPre = sinvoke borrowBalanceStored(e0, payer); + uint256 borrowerBorrowsPre = sinvoke borrowBalanceStored(e0, borrower); + uint256 otherBorrowsPre = sinvoke borrowBalanceStored(e0, other); + + uint256 cTokenTokensPre = sinvoke totalSupply(e0); + uint256 payerTokensPre = sinvoke balanceOf(e0, payer); + uint256 borrowerTokensPre = sinvoke balanceOf(e0, borrower); + uint256 otherTokensPre = sinvoke balanceOf(e0, other); + + uint256 cTokenReservesPre = sinvoke totalReserves(e0); + + // Just Do It + static_require result == invoke repayBorrowFreshPub(e1, payer, borrower, repayAmount); + bool repayBorrowFreshReverted = lastReverted; + + /* Post */ + + uint256 exchangeRatePost = sinvoke exchangeRateStored(e2); + + uint256 cTokenCashPost = sinvoke getCash(e2); + uint256 payerCashPost = sinvoke getCashOf(e2, payer); + uint256 borrowerCashPost = sinvoke getCashOf(e2, borrower); + uint256 otherCashPost = sinvoke getCashOf(e2, other); + + uint256 cTokenBorrowsPost = sinvoke totalBorrows(e2); + uint256 payerBorrowsPost = sinvoke borrowBalanceStored(e2, payer); + uint256 borrowerBorrowsPost = sinvoke borrowBalanceStored(e2, borrower); + uint256 otherBorrowsPost = sinvoke borrowBalanceStored(e2, other); + + uint256 cTokenTokensPost = sinvoke totalSupply(e2); + uint256 payerTokensPost = sinvoke balanceOf(e2, payer); + uint256 borrowerTokensPost = sinvoke balanceOf(e2, borrower); + uint256 otherTokensPost = sinvoke balanceOf(e2, other); + + uint256 cTokenReservesPost = sinvoke totalReserves(e2); + + // Measure + bool staticBalance = + (exchangeRatePost == exchangeRatePre) && + (cTokenCashPost == cTokenCashPre) && + (cTokenBorrowsPost == cTokenBorrowsPre) && + (cTokenTokensPost == cTokenTokensPre) && + (cTokenReservesPost == cTokenReservesPre) && + (payerCashPost == payerCashPre) && + (payerBorrowsPost == payerBorrowsPre) && + (payerTokensPost == payerTokensPre) && + (borrowerCashPost == borrowerCashPre) && + (borrowerBorrowsPost == borrowerBorrowsPre) && + (borrowerTokensPost == borrowerTokensPre) && + (otherCashPost == otherCashPre) && + (otherBorrowsPost == otherBorrowsPre) && + (otherTokensPost == otherTokensPre); + + // XXX more convenient way to represent uint max? + uint256 UINT_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935; + uint256 realRepayAmount; + static_require + ((repayAmount == UINT_MAX) => + (realRepayAmount == borrowerBorrowsPre)) && + ((repayAmount != UINT_MAX) => + (realRepayAmount == repayAmount)); + + uint256 payerBorrowsExpected; + uint256 borrowerCashExpected; + static_require + ((payer == borrower) => + (payerBorrowsExpected == payerBorrowsPre - realRepayAmount) && + (borrowerCashExpected == borrowerCashPre - realRepayAmount)) && + ((payer != borrower) => + (payerBorrowsExpected == payerBorrowsPre) && + (borrowerCashExpected == borrowerCashPre)); + + bool dynamicBalance = + (realRepayAmount != 0) && + (exchangeRatePost == exchangeRatePre) && + (cTokenCashPost == cTokenCashPre + realRepayAmount) && + (cTokenBorrowsPost == cTokenBorrowsPre - realRepayAmount) && + (cTokenTokensPost == cTokenTokensPre) && + (cTokenReservesPost == cTokenReservesPre) && + (payerCashPost == payerCashPre - realRepayAmount) && + (payerBorrowsPost == payerBorrowsExpected) && + (payerTokensPost == payerTokensPre) && + (borrowerCashPost == borrowerCashExpected) && + (borrowerBorrowsPost == borrowerBorrowsPre - realRepayAmount) && + (borrowerTokensPost == borrowerTokensPre) && + (otherCashPost == otherCashPre) && + (otherBorrowsPost == otherBorrowsPre) && + (otherTokensPost == otherTokensPre); + + // XXX would be nice to pull named enums from actual contract? + static_assert (!repayBorrowFreshReverted => + ((result != 0 || realRepayAmount == 0) <=> staticBalance)), "Mismatch in static case"; + static_assert (!repayBorrowFreshReverted => + ((result == 0 && realRepayAmount != 0 && payer != currentContract) <=> dynamicBalance)), "Mismatch in dynamic case"; +} diff --git a/spec/formal/compound.cvl b/spec/formal/compound.cvl new file mode 100644 index 000000000..eafe86ae9 --- /dev/null +++ b/spec/formal/compound.cvl @@ -0,0 +1,266 @@ +methods { +// taken from solc --hashes. Need to add "returns" +/*e9c714f2: */ _acceptAdmin() returns uint256 +/*5cf756d2: */ _setMarketInterestRateModel(address,address) returns uint256 +/*d9226ced: */ _setMaxAssets(uint256) returns uint256 +/*3be59443: */ _setOracle(address) returns uint256 +/*24021127: */ _setOriginationFee(uint256) returns uint256 +/*26617c28: */ _setPaused(bool) returns uint256 +/*b71d1a0c: */ _setPendingAdmin(address) returns uint256 +/*c365a646: */ _setRiskParameters(uint256,uint256) returns uint256 +/*c1abfaa3: */ _supportMarket(address,address) returns uint256 +/*dbe2bc84: */ _suspendMarket(address) returns uint256 +/*f851a440: */ admin() returns address +/*5e9a523c: */ assetPrices(address) returns uint256 +/*4b8a3529: */ borrow(address,uint256) returns uint256 +/*fc7d42d7: */ borrowBalances(address,address) returns uint256 +/*9f180cf1: */ calculateAccountValues(address) // TODO: returns (uint256, uint256, uint256) +/*beb54615: */ collateralMarkets(uint256) returns address +/*b4eae1cb: */ collateralRatio() returns uint256 +/*5ec88c79: */ getAccountLiquidity(address) // TODO: returns int256 +/*118e31b7: */ getBorrowBalance(address,address) returns uint256 +/*6e2ede03: */ getCollateralMarketsLength() returns uint256 +/*ba377731: */ getSupplyBalance(address,address) returns uint256 +/*e61604cf: */ liquidateBorrow(address,address,address,uint256) returns uint256 +/*8053fcbe: */ liquidationDiscount() returns uint256 +/*8e8f294b: */ markets(address) // TODO: returns market tuple +/*94b2294b: */ maxAssets() returns uint256 +/*7dc0d1d0: */ oracle() returns address +/*b8bb5c42: */ originationFee() returns uint256 +/*5c975abb: */ paused() // TODO: returns bool +/*26782247: */ pendingAdmin() returns address +/*abdb5ea8: */ repayBorrow(address,uint256) returns uint256 +/*f2b9fdb8: */ supply(address,uint256) returns uint256 +/*b7adddac: */ supplyBalances(address,address) returns uint256 +/*f3fef3a3: */ withdraw(address,uint256) returns uint256 +} + +_setOriginationFee(uint currentAdmin, uint currentFee, uint newOriginationFee) +description "Failed to set origination fee from $currentFee to $newOriginationFee (admin=$currentAdmin)" { + // Free Variables + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + // Strict ordering + static_require e1.block > e0.block; + static_require e2.block > e1.block; + + // Capture current admin and origination fee + static_require currentAdmin == sinvoke admin(e0); + static_require currentFee == sinvoke originationFee(e0); + + // Invoke set origination fee + uint256 result = sinvoke _setOriginationFee(e1, newOriginationFee); + + // originationFee changes <=> msg.sender == currentAdmin + static_assert ( + ( + e1.msg.sender == currentAdmin && + result == 0 && + sinvoke originationFee(e2) == newOriginationFee + ) + || + ( + e1.msg.sender != currentAdmin && + result != 0 && + sinvoke originationFee(e2) == currentFee + ) + ); +} + +_setPendingAdmin(address currentAdmin, address currentPendingAdmin, address newPendingAdmin) +description "Failed to set new pending admin $currentPendingAdmin to $newPendingAdmin (admin=$currentAdmin)" +{ + // Free Variables + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + // Strict ordering + static_require e1.block > e0.block; + static_require e2.block > e1.block; + + static_require currentAdmin == sinvoke admin(e0); + static_require currentPendingAdmin == sinvoke pendingAdmin(e0); + + // Invoke set new pending admin + uint256 result = sinvoke _setPendingAdmin(e1, newPendingAdmin); + + // pendingAdmin changes <=> msg.sender == currentAdmin + static_assert ( + ( + e1.msg.sender == currentAdmin && + result == 0 && + sinvoke pendingAdmin(e2) == newPendingAdmin + ) + || + ( + e1.msg.sender != currentAdmin && + result != 0 && + sinvoke pendingAdmin(e2) == currentPendingAdmin + ) + ); +} + +_acceptAdmin(address currentAdmin, address currentPendingAdmin, address newAdmin, address newPendingAdmin) +description "Failed to accept pending admin currentAdmin=$currentAdmin, currentPendingAdmin=$currentPendingAdmin, newPendingAdmin=$newPendingAdmin, newAdmin=$newAdmin" +{ + // Free Variables + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + // Strict ordering + static_require e1.block > e0.block; + static_require e2.block > e1.block; + + static_require currentAdmin == sinvoke admin(e0); + static_require currentPendingAdmin == sinvoke pendingAdmin(e0); + + // Invoke accept admin + uint256 result = sinvoke _acceptAdmin(e1); + + static_require newAdmin == sinvoke admin(e2); + static_require newPendingAdmin == sinvoke pendingAdmin(e2); + + // admin == pendingAdmin <=> msg.sender == pendingAdmin + static_assert ( + ( + e1.msg.sender == currentPendingAdmin && + currentPendingAdmin != 0 && + result == 0 && + newAdmin == currentPendingAdmin && + newPendingAdmin == 0 + ) + || + ( + ( + e1.msg.sender != currentPendingAdmin || + currentPendingAdmin == 0 + ) && + result != 0 && + newAdmin == currentAdmin && + newPendingAdmin == currentPendingAdmin + ) + ); +} + +// Invariant: To change admin or currentPendingAdmin, must come from current admin +invariantRequireAdminToChangeAdmin(address caller, address currentAdmin, address currentPendingAdmin, address desiredAdmin, address newAdmin, address newPendingAdmin) +description "Failed to prove that required to be admin to change admin (caller=$caller, currentAdmin=$currentAdmin, currentPendingAdmin=$currentPendingAdmin, desiredAdmin=$desiredAdmin, newAdmin=$newAdmin, newPendingAdmin=$newPendingAdmin)" +{ + // Free Variables + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + env e3; havoc e3; + + // Strict ordering (TODO: Can e2.block == e1.block?) + static_require e1.block > e0.block; + static_require e2.block > e1.block; + static_require e3.block > e2.block; + + static_require currentAdmin == sinvoke admin(e0); + static_require currentPendingAdmin == sinvoke pendingAdmin(e0); + + // Start with a zero admin + static_require currentPendingAdmin == 0; + + static_require caller == e1.msg.caller; + + // Invoke set new pending admin + uint256 result0 = sinvoke _setPendingAdmin(e1, desiredAdmin); + uint256 result1 = sinvoke _acceptAdmin(e2); + + static_require newAdmin == sinvoke admin(e3); + static_require newPendingAdmin == sinvoke pendingAdmin(e3); + + static_assert ( + e1.msg.sender == currentAdmin || + ( + newAdmin == currentAdmin && + newPendingAdmin == currentPendingAdmin + ) + ); +} + +_setOracle(address sender, address currAdmin, address currOracle, address desiredOracle, address nextOracle) +description "Failed to set oracle (sender=$sender, currAdmin=$currAdmin, currOracle=$currOracle, desiredOracle=$desiredOracle, nextOracle=$nextOracle)" { + // N.B. This merely havocs `oracleInterface.assetPrices(address(0))` + // and does not check or concern itself with the result. + + // Free Variables + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + // Strict ordering + static_require e1.block > e0.block; + static_require e2.block > e1.block; + + static_require currAdmin == sinvoke admin(e0); + static_require currOracle == sinvoke oracle(e0); + + static_require sender == e1.msg.sender; + + // Invoke set new pending admin + uint256 result = sinvoke _setOracle(e1, desiredOracle); + + static_require nextOracle == sinvoke oracle(e2); + + // nextOracle == desiredOracle <=> msg.sender == admin + static_assert ( + ( + sender == currAdmin && + result == 0 && + nextOracle == desiredOracle + ) + || + ( + sender != currAdmin && + result != 0 && + ( + // It's possible that we're trying to set + // it to what it previously was. This is + // really the same as "succeeding," since + // it does become (remain) what you set it to. + desiredOracle == currOracle || + nextOracle != desiredOracle + ) + ) + ); +} + +_setMaxAssets(address currentAdmin, uint newMaxAssets, uint oldMaxAssets) +description "Failed to set new maxAssets admin: $currentAdmin, new: $newMaxAssets, old: $old" +{ + // Free Variables + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + // Strict ordering + static_require e1.block > e0.block; + static_require e2.block > e1.block; + + static_require oldMaxAssets == sinvoke maxAssets(e0); + static_require currentAdmin == sinvoke admin(e0); + + // Invoke set new max assets + uint256 result = sinvoke _setMaxAssets(e1, newMaxAssets); + + static_assert ( + ( + e1.msg.sender == currentAdmin && + result == 0 && + sinvoke maxAssets(e2) == newMaxAssets + ) + || + ( + e1.msg.sender != currentAdmin && + result != 0 && + sinvoke maxAssets(e2) == oldMaxAssets + ) + ); +} diff --git a/spec/formal/contracts/CErc20Certora.sol b/spec/formal/contracts/CErc20Certora.sol new file mode 100644 index 000000000..ba4fa5c18 --- /dev/null +++ b/spec/formal/contracts/CErc20Certora.sol @@ -0,0 +1,164 @@ +pragma solidity ^0.5.8; + +import "../../../contracts/CErc20.sol"; +import "../../../contracts/EIP20Interface.sol"; + +import "./CTokenCollateral.sol"; +import "./SimulationInterface.sol"; + +contract CErc20Certora is CErc20 { + CTokenCollateral public otherToken; + + constructor(address underlying_, + ComptrollerInterface comptroller_, + InterestRateModel interestRateModel_, + uint initialExchangeRateMantissa_, + string memory name_, + string memory symbol_, + uint decimals_) public CErc20(underlying_, comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_) { + } + + function comptrollerMintAllowed(address currentContract, address minter, uint mintAmount) public returns (uint) { + return comptroller.mintAllowed(currentContract, minter, mintAmount); + } + + function comptrollerRedeemAllowed(address currentContract, address minter, uint mintAmount) public returns (uint) { + return comptroller.redeemAllowed(currentContract, minter, mintAmount); + } + + function exchangeRateStoredInternalPub() public view returns (MathError, uint) { + return exchangeRateStoredInternal(); + } + + function cTokenMintComputation(uint mintAmount) public returns (uint) { + MathError mathErr; + uint exchangeRateMantissa; + uint mintTokens; + + (mathErr, exchangeRateMantissa) = exchangeRateStoredInternal(); + require (mathErr == MathError.NO_ERROR); + + (mathErr, mintTokens) = divScalarByExpTruncate(mintAmount, Exp({mantissa: exchangeRateMantissa})); + require (mathErr == MathError.NO_ERROR); + + return mintTokens; + } + + function cTokenRedeemComputation(uint redeemTokens) public returns (uint) { + MathError mathErr; + uint exchangeRateMantissa; + uint redeemAmount; + + (mathErr, exchangeRateMantissa) = exchangeRateStoredInternal(); + require (mathErr == MathError.NO_ERROR); + + (mathErr, redeemAmount) = mulScalarTruncate(Exp({mantissa: exchangeRateMantissa}), redeemTokens); + require (mathErr == MathError.NO_ERROR); + + return redeemAmount; + } + + function checkTransferInPub(address from, uint amount) public view returns (uint) { + return uint(checkTransferIn(from,amount)); + } + + function doTransferInPub(address from, uint amount) public returns (uint) { + return uint(doTransferIn(from,amount)); + } + + function simulateUnderlying(uint expectedError) internal returns (uint) { + SimulationInterface token = SimulationInterface(underlying); + bool result; + + token.dummy(); + + // solium-disable-next-line security/no-inline-assembly + assembly { + switch returndatasize() + case 0 { // This is a non-standard ERC-20 + result := not(0) // set result to true + } + case 32 { // This is a complaint ERC-20 + returndatacopy(0, 0, 32) + result := mload(0) // Set `result = returndata` of external call + } + default { // This is an excessively non-compliant ERC-20, revert. + revert(0, 0) + } + } + + if (!result) { + return expectedError; + } + + return uint(Error.NO_ERROR); + } + + function doTransferInPubSim(address from, uint amount) public returns (uint) { + return simulateUnderlying(uint(Error.TOKEN_TRANSFER_IN_FAILED)); + } + + function doTransferOutPub(address payable to, uint amount) public returns (uint) { + return uint(doTransferOut(to, amount)); + } + + function doTransferOutPubSim(address payable to, uint amount) public returns (uint) { + return simulateUnderlying(uint(Error.TOKEN_TRANSFER_OUT_FAILED)); + } + + function balanceOfInOther(address account) public view returns (uint) { + return otherToken.balanceOf(account); + } + + function borrowBalanceStoredInOther(address account) public view returns (uint) { + return otherToken.borrowBalanceStored(account); + } + + function exchangeRateStoredInOther() public view returns (uint) { + return otherToken.exchangeRateStored(); + } + + function getCashInOther() public view returns (uint) { + return otherToken.getCash(); + } + + function getCashOf(address account) public view returns (uint) { + return EIP20Interface(underlying).balanceOf(account); + } + + function getCashOfInOther(address account) public view returns (uint) { + return otherToken.getCashOf(account); + } + + function totalSupplyInOther() public view returns (uint) { + return otherToken.totalSupply(); + } + + function totalBorrowsInOther() public view returns (uint) { + return otherToken.totalBorrows(); + } + + function totalReservesInOther() public view returns (uint) { + return otherToken.totalReserves(); + } + + function mintFreshPub(address minter, uint mintAmount) public returns (uint) { + return mintFresh(minter, mintAmount); + } + + function redeemFreshPub(address payable redeemer, uint redeemTokens, uint redeemUnderlying) public returns (uint) { + return redeemFresh(redeemer, redeemTokens, redeemUnderlying); + } + + function borrowFreshPub(address payable borrower, uint borrowAmount) public returns (uint) { + return borrowFresh(borrower, borrowAmount); + } + + function repayBorrowFreshPub(address payer, address borrower, uint repayAmount) public returns (uint) { + return repayBorrowFresh(payer, borrower, repayAmount); + } + + function liquidateBorrowFreshPub(address liquidator, address borrower, uint repayAmount) public returns (uint) { + return liquidateBorrowFresh(liquidator, borrower, repayAmount, otherToken); + } +} diff --git a/spec/formal/contracts/CEtherCertora.sol b/spec/formal/contracts/CEtherCertora.sol new file mode 100644 index 000000000..f6e8a6dd6 --- /dev/null +++ b/spec/formal/contracts/CEtherCertora.sol @@ -0,0 +1,13 @@ +pragma solidity ^0.5.8; + +import "../../../contracts/CEther.sol"; + +contract CEtherCertora is CEther { + constructor(ComptrollerInterface comptroller_, + InterestRateModel interestRateModel_, + uint initialExchangeRateMantissa_, + string memory name_, + string memory symbol_, + uint decimals_) public CEther(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_) { + } +} diff --git a/spec/formal/contracts/CTokenCollateral.sol b/spec/formal/contracts/CTokenCollateral.sol new file mode 100644 index 000000000..19e4957bb --- /dev/null +++ b/spec/formal/contracts/CTokenCollateral.sol @@ -0,0 +1,19 @@ +pragma solidity ^0.5.8; + +import "../../../contracts/CErc20.sol"; +import "../../../contracts/EIP20Interface.sol"; + +contract CTokenCollateral is CErc20 { + constructor(address underlying_, + ComptrollerInterface comptroller_, + InterestRateModel interestRateModel_, + uint initialExchangeRateMantissa_, + string memory name_, + string memory symbol_, + uint decimals_) public CErc20(underlying_, comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_) { + } + + function getCashOf(address account) public view returns (uint) { + return EIP20Interface(underlying).balanceOf(account); + } +} diff --git a/spec/formal/contracts/ComptrollerModel.sol b/spec/formal/contracts/ComptrollerModel.sol new file mode 100644 index 000000000..7586e0edd --- /dev/null +++ b/spec/formal/contracts/ComptrollerModel.sol @@ -0,0 +1,100 @@ +pragma solidity ^0.5.8; + +import "../../../contracts/CToken.sol"; + +contract ComptrollerModel { + uint mintAllowedResult; + uint redeemAllowedResult; + uint borrowAllowedResult; + uint repayBorrowAllowedResult; + uint liquidateBorrowAllowedResult; + uint seizeAllowedResult; + uint transferAllowedResult; + uint liquidateCalculateSeizeTokensResult1; + uint liquidateCalculateSeizeTokensResult2; + + + function mintAllowed(CToken cToken, address minter, uint mintAmount) public returns (uint) { + return mintAllowedResult; + } + + function mintVerify(CToken cToken, address minter, uint mintAmount, uint mintTokens) external {} + + + function redeemAllowed(CToken cToken, address redeemer, uint redeemTokens) public returns (uint) { + return redeemAllowedResult; + } + + function redeemVerify(CToken cToken, address redeemer, uint redeemAmount, uint redeemTokens) external {} + + + function borrowAllowed(CToken cToken, address borrower, uint borrowAmount) public returns (uint) { + return borrowAllowedResult; + } + + function borrowVerify(CToken cToken, address borrower, uint borrowAmount) external {} + + + function repayBorrowAllowed( + address cToken, + address payer, + address borrower, + uint repayAmount) external returns (uint) { + return repayBorrowAllowedResult; + } + + function repayBorrowVerify( + address cToken, + address payer, + address borrower, + uint repayAmount, + uint borrowerIndex) external {} + + + function liquidateBorrowAllowed( + address cTokenBorrowed, + address cTokenCollateral, + address liquidator, + address borrower, + uint repayAmount) external returns (uint) { + return liquidateBorrowAllowedResult; + } + + function liquidateBorrowVerify( + address cTokenBorrowed, + address cTokenCollateral, + address liquidator, + address borrower, + uint repayAmount, + uint seizeTokens) external {} + + + function seizeAllowed( + address cTokenCollateral, + address cTokenBorrowed, + address liquidator, + address borrower, + uint seizeTokens) external returns (uint) { + return seizeAllowedResult; + } + + function seizeVerify( + address cTokenCollateral, + address cTokenBorrowed, + address liquidator, + address borrower, + uint seizeTokens) external {} + + function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint) { + return transferAllowedResult; + } + + function transferVerify(address cToken, address src, address dst, uint transferTokens) external {} + + function liquidateCalculateSeizeTokens( + address cTokenBorrowed, + address cTokenCollateral, + uint repayAmount) external view returns (uint, uint) { + return (liquidateCalculateSeizeTokensResult1, liquidateCalculateSeizeTokensResult2); + } +} \ No newline at end of file diff --git a/spec/formal/contracts/MaximillionCertora.sol b/spec/formal/contracts/MaximillionCertora.sol new file mode 100644 index 000000000..4037e92db --- /dev/null +++ b/spec/formal/contracts/MaximillionCertora.sol @@ -0,0 +1,19 @@ +pragma solidity ^0.5.8; + +import "../../../contracts/Maximillion.sol"; + +contract MaximillionCertora is Maximillion { + constructor(CEther cEther_) public Maximillion(cEther_) {} + + function borrowBalance(address account) external returns (uint) { + return cEther.borrowBalanceCurrent(account); + } + + function etherBalance(address account) external returns (uint) { + return account.balance; + } + + function repayBehalf(address borrower) public payable { + return super.repayBehalf(borrower); + } +} \ No newline at end of file diff --git a/spec/formal/contracts/SimulationInterface.sol b/spec/formal/contracts/SimulationInterface.sol new file mode 100644 index 000000000..91af008d3 --- /dev/null +++ b/spec/formal/contracts/SimulationInterface.sol @@ -0,0 +1,5 @@ +pragma solidity ^0.5.8; + +interface SimulationInterface { + function dummy() external; +} diff --git a/spec/formal/contracts/UnderlyingModelNonStandard.sol b/spec/formal/contracts/UnderlyingModelNonStandard.sol new file mode 100644 index 000000000..d8c27522b --- /dev/null +++ b/spec/formal/contracts/UnderlyingModelNonStandard.sol @@ -0,0 +1,55 @@ +pragma solidity ^0.5.8; + +import "../../../contracts/EIP20NonStandardInterface.sol"; + +import "./SimulationInterface.sol"; + +contract UnderlyingModelNonStandard is EIP20NonStandardInterface, SimulationInterface { + uint256 _totalSupply; + mapping (address => uint256) balances; + mapping (address => mapping (address => uint256)) allowances; + + function totalSupply() external view returns (uint256) { + return _totalSupply; + } + + /** + * @notice Gets the balance of the specified address + * @param owner The address from which the balance will be retrieved + * @return The balance + */ + function balanceOf(address owner) external view returns (uint256 balance) { + balance = balances[owner]; + } + + function transfer(address dst, uint256 amount) external { + address src = msg.sender; + require (balances[src]>=amount); + require (balances[dst]+amount>=balances[dst]); + + balances[src] -= amount; + balances[dst] += amount; + } + + function transferFrom(address src, address dst, uint256 amount) external { + require (allowances[src][msg.sender] >= amount); + require (balances[src]>=amount); + require (balances[dst]+amount>=balances[dst]); + + allowances[src][msg.sender] -= amount; + balances[src] -= amount; + balances[dst] += amount; + } + + function approve(address spender, uint256 amount) external returns (bool success) { + allowances[msg.sender][spender] = amount; + } + + function allowance(address owner, address spender) external view returns (uint256 remaining) { + remaining = allowances[owner][spender]; + } + + function dummy() external { + return; + } +} \ No newline at end of file diff --git a/spec/formal/dummy.cvl b/spec/formal/dummy.cvl new file mode 100644 index 000000000..82ccf67ed --- /dev/null +++ b/spec/formal/dummy.cvl @@ -0,0 +1 @@ +// hello diff --git a/spec/formal/eip20.cvl b/spec/formal/eip20.cvl new file mode 100644 index 000000000..e5654d78a --- /dev/null +++ b/spec/formal/eip20.cvl @@ -0,0 +1,154 @@ +methods { + totalSupply() returns uint256 + totalBorrows() returns uint256 + totalReserves() returns uint256 + + balanceOf(address) returns uint256 + borrowBalanceStored(address) returns uint256 + exchangeRateStored() returns uint256 + + getCash() returns uint256 + getCashOf(address) returns uint256 // not part of API + + allowance(address, address) returns uint256 + approve(address, uint256) returns bool + transferFrom(address, address, uint256) returns bool +} + +transferFrom(bool success, address src, address dst, uint256 amount) +description "Break transferFrom" { + // Pre/action/post environments + env e0; havoc e0; + env e1a; havoc e1a; + env e1b; havoc e1b; + env e2; havoc e2; + + static_require e1a.block.number >= e0.block.number; + static_require e1b.block.number >= e1a.block.number; + static_require e2.block.number >= e1b.block.number; + + // Any other account + address other; havoc other; + static_require other != src && other != dst; + + /* + - no effect on exchange rate + - no more than approved + |----------+--------+-----+-----+-------| + | | CToken | Src | Dst | Other | + |----------+--------+-----+-----+-------| + | cash | 0 | 0 | 0 | 0 | + | borrows | 0 | 0 | 0 | 0 | + | tokens | 0 | -T | +T | 0 | + | reserves | 0 | | | | + |----------+--------+-----+-----+-------| + */ + + /* Pre */ + + uint256 exchangeRatePre = sinvoke exchangeRateStored(e0); + + uint256 cTokenCashPre = sinvoke getCash(e0); + uint256 srcCashPre = sinvoke getCashOf(e0, src); + uint256 dstCashPre = sinvoke getCashOf(e0, dst); + uint256 otherCashPre = sinvoke getCashOf(e0, other); + + uint256 cTokenBorrowsPre = sinvoke totalBorrows(e0); + uint256 srcBorrowsPre = sinvoke borrowBalanceStored(e0, src); + uint256 dstBorrowsPre = sinvoke borrowBalanceStored(e0, dst); + uint256 otherBorrowsPre = sinvoke borrowBalanceStored(e0, other); + + uint256 cTokenSupplyPre = sinvoke totalSupply(e0); + uint256 srcTokensPre = sinvoke balanceOf(e0, src); + uint256 dstTokensPre = sinvoke balanceOf(e0, dst); + uint256 otherTokensPre = sinvoke balanceOf(e0, other); + + uint256 cTokenReservesPre = sinvoke totalReserves(e0); + + // Approve + bool doApprove; havoc doApprove; + uint256 approvedAmount; havoc approvedAmount; + if (doApprove) { + static_require e1a.msg.sender == src; + sinvoke approve(e1a, e1b.msg.sender, approvedAmount); + } else {} + + uint256 allowancePre = sinvoke allowance(e1a, src, e1b.msg.sender); + + // Just Do It + static_require success == invoke transferFrom(e1b, src, dst, amount); + bool transferReverted = lastReverted; + + /* Post */ + + uint256 exchangeRatePost = sinvoke exchangeRateStored(e2); + + uint256 cTokenCashPost = sinvoke getCash(e2); + uint256 srcCashPost = sinvoke getCashOf(e2, src); + uint256 dstCashPost = sinvoke getCashOf(e2, dst); + uint256 otherCashPost = sinvoke getCashOf(e2, other); + + uint256 cTokenBorrowsPost = sinvoke totalBorrows(e2); + uint256 srcBorrowsPost = sinvoke borrowBalanceStored(e2, src); + uint256 dstBorrowsPost = sinvoke borrowBalanceStored(e2, dst); + uint256 otherBorrowsPost = sinvoke borrowBalanceStored(e2, other); + + uint256 cTokenSupplyPost = sinvoke totalSupply(e2); + uint256 srcTokensPost = sinvoke balanceOf(e2, src); + uint256 dstTokensPost = sinvoke balanceOf(e2, dst); + uint256 otherTokensPost = sinvoke balanceOf(e2, other); + + uint256 cTokenReservesPost = sinvoke totalReserves(e2); + + uint256 allowancePost = sinvoke allowance(e2, src, e1b.msg.sender); + + // Measure + bool staticBalance = + (exchangeRatePost == exchangeRatePre) && + (cTokenCashPost == cTokenCashPre) && + (cTokenBorrowsPost == cTokenBorrowsPre) && + (cTokenSupplyPost == cTokenSupplyPre) && + (cTokenReservesPost == cTokenReservesPre) && + (srcCashPost == srcCashPre) && + (srcBorrowsPost == srcBorrowsPre) && + (srcTokensPost == srcTokensPre) && + (dstCashPost == dstCashPre) && + (dstBorrowsPost == dstBorrowsPre) && + (dstTokensPost == dstTokensPre) && + (otherCashPost == otherCashPre) && + (otherBorrowsPost == otherBorrowsPre) && + (otherTokensPost == otherTokensPre); + + bool dynamicBalance = + (amount != 0) && + (exchangeRatePost == exchangeRatePre) && + (cTokenCashPost == cTokenCashPre) && + (cTokenBorrowsPost == cTokenBorrowsPre) && + (cTokenSupplyPost == cTokenSupplyPre) && + (cTokenReservesPost == cTokenReservesPre) && + (srcCashPost == srcCashPre) && + (srcBorrowsPost == srcBorrowsPre) && + (srcTokensPost == srcTokensPre - amount) && + (dstCashPost == dstCashPre) && + (dstBorrowsPost == dstBorrowsPre) && + (dstTokensPost == dstTokensPre + amount) && + (otherCashPost == otherCashPre) && + (otherBorrowsPost == otherBorrowsPre) && + (otherTokensPost == otherTokensPre); + + // XXX better way to write uint max? + uint256 UINT_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + static_assert (!transferReverted => + ((!success || amount == 0 || src == dst) <=> staticBalance)), "Mismatch in static case"; + static_assert (!transferReverted => + ((success && amount != 0) <=> dynamicBalance)), "Mismatch in dynamic case"; + static_assert (!transferReverted && success => + (amount > allowancePre => e1b.msg.sender == src)), "Only owner can transfer > allowance"; + static_assert (!transferReverted && success => + (doApprove => allowancePre >= approvedAmount)), "Approval must increase the allowance"; + static_assert (!transferReverted && success => + (allowancePre == UINT_MAX || e1b.msg.sender == src || amount == 0) <=> allowancePost == allowancePre), "Mismatch not touching allowance"; + static_assert (!transferReverted && success && e1b.msg.sender != src && amount != 0 => + (allowancePre != UINT_MAX <=> allowancePost == allowancePre - amount)), "Spender transfer uses allowance"; +} \ No newline at end of file diff --git a/spec/formal/frame.cvl b/spec/formal/frame.cvl new file mode 100644 index 000000000..877ae3393 --- /dev/null +++ b/spec/formal/frame.cvl @@ -0,0 +1,359 @@ +methods { +/*70a08231:*/ balanceOf(address) returns uint256 +/*95dd9193:*/ borrowBalanceStored(address) returns uint256 +/*aa5af0fd:*/ borrowIndex() returns uint256 +/*f8f9da28:*/ borrowRatePerBlock() returns uint256 +/*5fe3b567:*/ comptroller() returns address +/*182df0f5:*/ exchangeRateStored() returns uint256 +/*c37f68e2:*/ getAccountSnapshot(address) returns uint256,uint256,uint256,uint256 +/*3b1d21a2:*/ getCash() returns uint256 +/*675d972c:*/ initialExchangeRateMantissa() returns uint256 +/*f3fdb15a:*/ interestRateModel() returns address +/*fe9c44ae:*/ isCToken() returns bool +/*26782247:*/ pendingAdmin() returns address +/*173b9904:*/ reserveFactorMantissa() returns uint256 +/*ae9d70b0:*/ supplyRatePerBlock() returns uint256 +/*47bd3718:*/ totalBorrows() returns uint256 +/*8f840ddd:*/ totalReserves() returns uint256 +/*18160ddd:*/ totalSupply() returns uint256 + + +// all other methods +/*e9c714f2:*/ _acceptAdmin() +/*601a0bf1:*/ _reduceReserves(uint256) +/*4576b5db:*/ _setComptroller(address) +/*f2b3abbd:*/ _setInterestRateModel(address) +/*b71d1a0c:*/ _setPendingAdmin(address) +/*fca7820b:*/ _setReserveFactor(uint256) +/*6c540baf:*/ accrualBlockNumber() +/*a6afed95:*/ accrueInterest() +/*f851a440:*/ admin() +/*dd62ed3e:*/ allowance(address,address) +/*095ea7b3:*/ approve(address,uint256) +/*3af9e669:*/ balanceOfUnderlying(address) +/*c5ebeaec:*/ borrow(uint256) +/*17bfdfbc:*/ borrowBalanceCurrent(address) +/*0bc1d628:*/ borrowFreshPub(address,uint256) +/*5d2b2256:*/ cTokenMintComputation(uint256) +/*f1651460:*/ cTokenRedeemComputation(uint256) +/*b8b8b26b:*/ checkTransferInPub(address,uint256) +/*d9d9e5e5:*/ comptrollerMintAllowed(address,address,uint256) +/*92ac96fa:*/ comptrollerRedeemAllowed(address,address,uint256) +/*313ce567:*/ decimals() +/*19ec23ba:*/ doTransferInPub(address,uint256) +/*f782def5:*/ doTransferInPubSim(address,uint256) +/*b5d229bb:*/ doTransferOutPub(address,uint256) +/*18628ce7:*/ doTransferOutPubSim(address,uint256) +/*bd6d894d:*/ exchangeRateCurrent() +/*934213e8:*/ exchangeRateStoredInternalPub() +/*f414bbaf:*/ getCashOf(address) +/*5b1c10f6:*/ getCashPub() +/*529ca4b7:*/ interestRateModelGetBorrowRate() +/*f5e3c462:*/ liquidateBorrow(address,uint256,address) +/*a0712d68:*/ mint(uint256) +/*c9645990:*/ mintFreshPub(address,uint256) +/*06fdde03:*/ name() +/*db006a75:*/ redeem(uint256) +/*8c1a1b80:*/ redeemFreshPub(address,uint256,uint256) +/*852a12e3:*/ redeemUnderlying(uint256) +/*0e752702:*/ repayBorrow(uint256) +/*2608f818:*/ repayBorrowBehalf(address,uint256) +/*7a6a0162:*/ repayBorrowFreshPub(address,address,uint256) +/*b2a02ff1:*/ seize(address,address,uint256) +/*95d89b41:*/ symbol() +/*73acee98:*/ totalBorrowsCurrent() +/*a9059cbb:*/ transfer(address,uint256) +/*23b872dd:*/ transferFrom(address,address,uint256) +/*6f307dc3:*/ underlying() +} + +frame_balanceOf(address a, method f) +description "$f may change value of balanceOf($a)" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + uint256 old = sinvoke balanceOf(e0, a); + calldataarg arg; + invoke f(e1, arg); + uint256 new = sinvoke balanceOf(e2, a); + + static_assert old == new; +} + +frame_borrowBalanceStored(address a, method f) +description "$f may change value of borrowBalanceStored($a)" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + uint256 old = sinvoke borrowBalanceStored(e0, a); + calldataarg arg; + invoke f(e1, arg); + uint256 new = sinvoke borrowBalanceStored(e2, a); + + static_assert old == new; +} + +frame_borrowIndex(method f) +description "$f may change value of borrowIndex()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + uint256 old = sinvoke borrowIndex(e0); + calldataarg arg; + invoke f(e1, arg); + uint256 new = sinvoke borrowIndex(e2); + + static_assert old == new; +} + +frame_borrowRatePerBlock(method f) +description "$f may change value of borrowRatePerBlock()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + uint256 old = sinvoke borrowRatePerBlock(e0); + calldataarg arg; + invoke f(e1, arg); + uint256 new = sinvoke borrowRatePerBlock(e2); + + static_assert old == new; +} + +frame_comptroller(method f) +description "$f may change value of comptroller()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + address old = sinvoke comptroller(e0); + calldataarg arg; + invoke f(e1, arg); + address new = sinvoke comptroller(e2); + + static_assert old == new; +} + +frame_exchangeRateStored(address a, method f) +description "$f may change value of exchangeRateStored()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + uint256 old = sinvoke exchangeRateStored(e0); + calldataarg arg; + invoke f(e1, arg); + uint256 new = sinvoke exchangeRateStored(e2); + + static_assert old == new; +} + +frame_getAccountSnapshot(address a, method f) +description "$f may change value of getAccountSnapshot($a)" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + uint256 old1; uint256 old2; uint256 old3; uint256 old4; + old1,old2,old3,old4 = sinvoke getAccountSnapshot(e0, a); + calldataarg arg; + invoke f(e1, arg); + uint256 new1; uint256 new2; uint256 new3; uint256 new4; + new1,new2,new3,new4 = sinvoke getAccountSnapshot(e2, a); + + static_assert old1 == new1 && old2 == new2 && old3 == new3 && old4 == new4; +} + +frame_getCash(method f) +description "$f may change value of getCash()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + uint256 old = sinvoke getCash(e0); + calldataarg arg; + invoke f(e1, arg); + uint256 new = sinvoke getCash(e2); + + static_assert old == new; +} + +frame_initialExchangeRateMantissa(method f) +description "$f may change value of initialExchangeRateMantissa()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + uint256 old = sinvoke initialExchangeRateMantissa(e0); + calldataarg arg; + invoke f(e1, arg); + uint256 new = sinvoke initialExchangeRateMantissa(e2); + + static_assert old == new; +} + +frame_interestRateModel(method f) +description "$f may change value of interestRateModel()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + address old = sinvoke interestRateModel(e0); + calldataarg arg; + invoke f(e1, arg); + address new = sinvoke interestRateModel(e2); + + static_assert old == new; +} + +frame_isCToken(method f) +description "$f may change value of isCToken()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + bool old = sinvoke isCToken(e0); + calldataarg arg; + invoke f(e1, arg); + bool new = sinvoke isCToken(e2); + + static_assert old == new; +} + +frame_pendingAdmin(method f) +description "$f may change value of pendingAdmin()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + address old = sinvoke pendingAdmin(e0); + calldataarg arg; + invoke f(e1, arg); + address new = sinvoke pendingAdmin(e2); + + static_assert old == new; +} + +frame_reserveFactorMantissa(method f) +description "$f may change value of reserveFactorMantissa()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + uint256 old = sinvoke reserveFactorMantissa(e0); + calldataarg arg; + invoke f(e1, arg); + uint256 new = sinvoke reserveFactorMantissa(e2); + + static_assert old == new; +} + +frame_supplyRatePerBlock(method f) +description "$f may change value of supplyRatePerBlock()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + uint256 old = sinvoke supplyRatePerBlock(e0); + calldataarg arg; + invoke f(e1, arg); + uint256 new = sinvoke supplyRatePerBlock(e2); + + static_assert old == new; +} + +frame_totalBorrows(method f) +description "$f may change value of totalBorrows()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + uint256 old = sinvoke totalBorrows(e0); + calldataarg arg; + invoke f(e1, arg); + uint256 new = sinvoke totalBorrows(e2); + + static_assert old == new; +} + +frame_totalReserves(address a, method f) +description "$f may change value of totalReserves()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + uint256 old = sinvoke totalReserves(e0); + calldataarg arg; + invoke f(e1, arg); + uint256 new = sinvoke totalReserves(e2); + + static_assert old == new; +} + +frame_totalSupply(method f) +description "$f may change value of totalSupply()" +{ + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + uint256 old = sinvoke totalSupply(e0); + calldataarg arg; + invoke f(e1, arg); + uint256 new = sinvoke totalSupply(e2); + + static_assert old == new; +} \ No newline at end of file diff --git a/spec/formal/general.cvl b/spec/formal/general.cvl new file mode 100644 index 000000000..b87bb9797 --- /dev/null +++ b/spec/formal/general.cvl @@ -0,0 +1,167 @@ +methods { + _setPendingAdmin(address) returns uint256 + pendingAdmin() returns address + + _acceptAdmin() returns uint256 + admin() returns address + + _setComptroller(address) returns uint256 + comptroller() returns address +} + +_setPendingAdmin(address currentAdmin, address currentPendingAdmin, address newPendingAdmin) +description "Failed to set new pending admin $currentPendingAdmin to $newPendingAdmin (admin=$currentAdmin)" +{ + // Free Variables + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + // Strict ordering + static_require e1.block > e0.block; + static_require e2.block > e1.block; + + static_require currentAdmin == sinvoke admin(e0); + static_require currentPendingAdmin == sinvoke pendingAdmin(e0); + + // Invoke set new pending admin + uint256 result = sinvoke _setPendingAdmin(e1, newPendingAdmin); + + // pendingAdmin changes <=> msg.sender == currentAdmin + static_assert ( + ( + e1.msg.sender == currentAdmin && + result == 0 && + sinvoke pendingAdmin(e2) == newPendingAdmin + ) + || + ( + e1.msg.sender != currentAdmin && + result != 0 && + sinvoke pendingAdmin(e2) == currentPendingAdmin + ) + ); +} + +_acceptAdmin(address currentAdmin, address currentPendingAdmin, address newAdmin, address newPendingAdmin) + description "Failed to accept pending admin currentAdmin=$currentAdmin, currentPendingAdmin=$currentPendingAdmin, newPendingAdmin=$newPendingAdmin, newAdmin=$newAdmin" +{ + // Free Variables + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + // Strict ordering + static_require e1.block > e0.block; + static_require e2.block > e1.block; + + static_require currentAdmin == sinvoke admin(e0); + static_require currentPendingAdmin == sinvoke pendingAdmin(e0); + + // Invoke accept admin + uint256 result = sinvoke _acceptAdmin(e1); + + static_require newAdmin == sinvoke admin(e2); + static_require newPendingAdmin == sinvoke pendingAdmin(e2); + + // admin == pendingAdmin <=> msg.sender == pendingAdmin + static_assert ( + ( + e1.msg.sender == currentPendingAdmin && + currentPendingAdmin != 0 && + result == 0 && + newAdmin == currentPendingAdmin && + newPendingAdmin == 0 + ) + || + ( + ( + e1.msg.sender != currentPendingAdmin || + currentPendingAdmin == 0 + ) && + result != 0 && + newAdmin == currentAdmin && + newPendingAdmin == currentPendingAdmin + ) + ); +} + +// Invariant: To change admin or currentPendingAdmin, must come from current admin +invariantRequireAdminToChangeAdmin(address caller, address currentAdmin, address currentPendingAdmin, address desiredAdmin, address newAdmin, address newPendingAdmin) + description "Failed to prove that required to be admin to change admin (caller=$caller, currentAdmin=$currentAdmin, currentPendingAdmin=$currentPendingAdmin, desiredAdmin=$desiredAdmin, newAdmin=$newAdmin, newPendingAdmin=$newPendingAdmin)" +{ + // Free Variables + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + env e3; havoc e3; + + // Strict ordering (TODO: Can e2.block == e1.block?) + static_require e1.block > e0.block; + static_require e2.block > e1.block; + static_require e3.block > e2.block; + + static_require currentAdmin == sinvoke admin(e0); + static_require currentPendingAdmin == sinvoke pendingAdmin(e0); + + // Start with a zero admin + static_require currentPendingAdmin == 0; + + static_require caller == e1.msg.caller; + + // Invoke set new pending admin + uint256 result0 = sinvoke _setPendingAdmin(e1, desiredAdmin); + uint256 result1 = sinvoke _acceptAdmin(e2); + + static_require newAdmin == sinvoke admin(e3); + static_require newPendingAdmin == sinvoke pendingAdmin(e3); + + static_assert ( + e1.msg.sender == currentAdmin || + ( + newAdmin == currentAdmin && + newPendingAdmin == currentPendingAdmin + ) + ); +} + +_setComptroller(address sender, address currAdmin, address currComptroller, address desiredComptroller, address nextComptroller) + description "Failed to set comptroller: result=$result (sender=$sender, currAdmin=$currAdmin, currComptroller=$currComptroller, desiredComptroller=$desiredComptroller, nextComptroller=$nextComptroller)" { + // N.B. This merely havocs `oracleInterface.assetPrices(address(0))` + // and does not check or concern itself with the result. + + // Free Variables + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + // Strict ordering + static_require e1.block > e0.block; + static_require e2.block > e1.block; + + static_require currAdmin == sinvoke admin(e0); + static_require currComptroller == sinvoke comptroller(e0); + + static_require sender == e1.msg.sender; + + // Invoke set new comptroller + uint256 result = sinvoke _setComptroller(e1, desiredComptroller); + + static_require nextComptroller == sinvoke comptroller(e2); + + // nextComptroller == desiredComptroller <=> msg.sender == admin + static_assert ((sender == currAdmin && + result == 0 && + nextComptroller == desiredComptroller) + || + (sender != currAdmin && + result == 1 && // UNAUTHORIZED + ( + // It's possible that we're trying to set + // it to what it previously was. This is + // really the same as "succeeding," since + // it does become (remain) what you set it to. + desiredComptroller == currComptroller || + nextComptroller != desiredComptroller + ))); +} diff --git a/spec/formal/liquidateFresh.cvl b/spec/formal/liquidateFresh.cvl new file mode 100644 index 000000000..8b8e9c5ab --- /dev/null +++ b/spec/formal/liquidateFresh.cvl @@ -0,0 +1,331 @@ +methods { + totalSupply() returns uint256 + totalSupplyInOther() returns uint256 // not part of API + totalBorrows() returns uint256 + totalBorrowsInOther() returns uint256 // not part of API + totalReserves() returns uint256 + totalReservesInOther() returns uint256 // not part of API + + balanceOf(address) returns uint256 + balanceOfInOther(address) returns uint256 // not part of API + borrowBalanceStored(address) returns uint256 + borrowBalanceStoredInOther(address) returns uint256 // not part of API + exchangeRateStored() returns uint256 + exchangeRateStoredInOther() returns uint256 // not part of API + + getCash() returns uint256 + getCashInOther() returns uint256 // not part of API + getCashOf(address) returns uint256 // not part of API + getCashOfInOther(address) returns uint256 // not part of API + + liquidateBorrowFreshPub(address, address, uint256) returns uint256 + seize(address, address, uint256) returns uint256 +} + +liquidateBorrowFresh(uint result, address liquidator, address borrower, uint256 repayAmount) +description "Break liquidate" { + // Pre/action/post environments + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + // Any other account + address other; havoc other; + static_require other != liquidator && other != borrower && other != currentContract; + + // We assume this cannot happen + // OQ: should we enforce in the code such that it need not be assumed? + static_require borrower != currentContract; + + /* + - no effect on exchange rate + - self-liquidate has no effect + |---------------------+--------+------------+----------+-------| + | | CToken | Liquidator | Borrower | Other | + |---------------------+--------+------------+----------+-------| + | cash | +A | -A | 0 | 0 | + | borrows | -A | 0 | -A | 0 | + | tokens | 0 | 0 | 0 | 0 | + | reserves | 0 | | | | + | collateral cash | 0 | 0 | 0 | 0 | + | collateral borrows | 0 | 0 | 0 | 0 | + | collateral tokens | 0 | +T | -T | 0 | + | collateral reserves | 0 | | | | + |---------------------+--------+------------+----------+-------| + */ + + /* Pre */ + + // borrowed + uint256 exchangeRatePre = sinvoke exchangeRateStored(e0); + + uint256 cTokenCashPre = sinvoke getCash(e0); + uint256 liquidatorCashPre = sinvoke getCashOf(e0, liquidator); + uint256 borrowerCashPre = sinvoke getCashOf(e0, borrower); + uint256 otherCashPre = sinvoke getCashOf(e0, other); + + uint256 cTokenBorrowsPre = sinvoke totalBorrows(e0); + uint256 liquidatorBorrowsPre = sinvoke borrowBalanceStored(e0, liquidator); + uint256 borrowerBorrowsPre = sinvoke borrowBalanceStored(e0, borrower); + uint256 otherBorrowsPre = sinvoke borrowBalanceStored(e0, other); + + uint256 cTokenTokensPre = sinvoke totalSupply(e0); + uint256 liquidatorTokensPre = sinvoke balanceOf(e0, liquidator); + uint256 borrowerTokensPre = sinvoke balanceOf(e0, borrower); + uint256 otherTokensPre = sinvoke balanceOf(e0, other); + + uint256 cTokenReservesPre = sinvoke totalReserves(e0); + + // collateral + uint256 collateralExchangeRatePre = sinvoke exchangeRateStoredInOther(e0); + + uint256 collateralCashPre = sinvoke getCashInOther(e0); + uint256 liquidatorCollateralCashPre = sinvoke getCashOfInOther(e0, liquidator); + uint256 borrowerCollateralCashPre = sinvoke getCashOfInOther(e0, borrower); + uint256 otherCollateralCashPre = sinvoke getCashOfInOther(e0, other); + + uint256 collateralBorrowsPre = sinvoke totalBorrowsInOther(e0); + uint256 liquidatorCollateralBorrowsPre = sinvoke borrowBalanceStoredInOther(e0, liquidator); + uint256 borrowerCollateralBorrowsPre = sinvoke borrowBalanceStoredInOther(e0, borrower); + uint256 otherCollateralBorrowsPre = sinvoke borrowBalanceStoredInOther(e0, other); + + uint256 collateralTokensPre = sinvoke totalSupplyInOther(e0); + uint256 liquidatorCollateralTokensPre = sinvoke balanceOfInOther(e0, liquidator); + uint256 borrowerCollateralTokensPre = sinvoke balanceOfInOther(e0, borrower); + uint256 otherCollateralTokensPre = sinvoke balanceOfInOther(e0, other); + + uint256 collateralReservesPre = sinvoke totalReservesInOther(e0); + + // Just Do It + // Note: cTokenCollateral is linked via Compound.spclnk in order to support checking its balances + // not perfect since it only proves the balance sheet is safe for a particular token configuration + static_require result == invoke liquidateBorrowFreshPub(e1, liquidator, borrower, repayAmount); + bool liquidateBorrowFreshReverted = lastReverted; + + /* Post */ + + // borrowed + uint256 exchangeRatePost = sinvoke exchangeRateStored(e2); + + uint256 cTokenCashPost = sinvoke getCash(e2); + uint256 liquidatorCashPost = sinvoke getCashOf(e2, liquidator); + uint256 borrowerCashPost = sinvoke getCashOf(e2, borrower); + uint256 otherCashPost = sinvoke getCashOf(e2, other); + + uint256 cTokenBorrowsPost = sinvoke totalBorrows(e2); + uint256 liquidatorBorrowsPost = sinvoke borrowBalanceStored(e2, liquidator); + uint256 borrowerBorrowsPost = sinvoke borrowBalanceStored(e2, borrower); + uint256 otherBorrowsPost = sinvoke borrowBalanceStored(e2, other); + + uint256 cTokenTokensPost = sinvoke totalSupply(e2); + uint256 liquidatorTokensPost = sinvoke balanceOf(e2, liquidator); + uint256 borrowerTokensPost = sinvoke balanceOf(e2, borrower); + uint256 otherTokensPost = sinvoke balanceOf(e2, other); + + uint256 cTokenReservesPost = sinvoke totalReserves(e2); + + // collateral + uint256 collateralExchangeRatePost = sinvoke exchangeRateStoredInOther(e2); + + uint256 collateralCashPost = sinvoke getCashInOther(e2); + uint256 liquidatorCollateralCashPost = sinvoke getCashOfInOther(e2, liquidator); + uint256 borrowerCollateralCashPost = sinvoke getCashOfInOther(e2, borrower); + uint256 otherCollateralCashPost = sinvoke getCashOfInOther(e2, other); + + uint256 collateralBorrowsPost = sinvoke totalBorrowsInOther(e2); + uint256 liquidatorCollateralBorrowsPost = sinvoke borrowBalanceStoredInOther(e2, liquidator); + uint256 borrowerCollateralBorrowsPost = sinvoke borrowBalanceStoredInOther(e2, borrower); + uint256 otherCollateralBorrowsPost = sinvoke borrowBalanceStoredInOther(e2, other); + + uint256 collateralTokensPost = sinvoke totalSupplyInOther(e2); + uint256 liquidatorCollateralTokensPost = sinvoke balanceOfInOther(e2, liquidator); + uint256 borrowerCollateralTokensPost = sinvoke balanceOfInOther(e2, borrower); + uint256 otherCollateralTokensPost = sinvoke balanceOfInOther(e2, other); + + uint256 collateralReservesPost = sinvoke totalReservesInOther(e2); + + // Measure + bool staticBalance = + (exchangeRatePost == exchangeRatePre) && + (cTokenCashPost == cTokenCashPre) && + (cTokenBorrowsPost == cTokenBorrowsPre) && + (cTokenTokensPost == cTokenTokensPre) && + (cTokenReservesPost == cTokenReservesPre) && + (liquidatorCashPost == liquidatorCashPre) && + (liquidatorBorrowsPost == liquidatorBorrowsPre) && + (liquidatorTokensPost == liquidatorTokensPre) && + (borrowerCashPost == borrowerCashPre) && + (borrowerBorrowsPost == borrowerBorrowsPre) && + (borrowerTokensPost == borrowerTokensPre) && + (otherCashPost == otherCashPre) && + (otherBorrowsPost == otherBorrowsPre) && + (otherTokensPost == otherTokensPre) && + + (collateralExchangeRatePost == collateralExchangeRatePre) && + (collateralCashPost == collateralCashPre) && + (collateralBorrowsPost == collateralBorrowsPre) && + (collateralTokensPost == collateralTokensPre) && + (collateralReservesPost == collateralReservesPre) && + (liquidatorCollateralCashPost == liquidatorCollateralCashPre) && + (liquidatorCollateralBorrowsPost == liquidatorCollateralBorrowsPre) && + (liquidatorCollateralTokensPost == liquidatorCollateralTokensPre) && + (borrowerCollateralCashPost == borrowerCollateralCashPre) && + (borrowerCollateralBorrowsPost == borrowerCollateralBorrowsPre) && + (borrowerCollateralTokensPost == borrowerCollateralTokensPre) && + (otherCollateralCashPost == otherCollateralCashPre) && + (otherCollateralBorrowsPost == otherCollateralBorrowsPre) && + (otherCollateralTokensPost == otherCollateralTokensPre); + + bool dynamicBalance = + (repayAmount != 0) && + (exchangeRatePost == exchangeRatePre) && + (cTokenCashPost == cTokenCashPre + repayAmount) && + (cTokenBorrowsPost == cTokenBorrowsPre - repayAmount) && + (cTokenTokensPost == cTokenTokensPre) && + (cTokenReservesPost == cTokenReservesPre) && + (liquidatorCashPost == liquidatorCashPre - repayAmount) && + (liquidatorBorrowsPost == liquidatorBorrowsPre) && + (liquidatorTokensPost == liquidatorTokensPre) && + (borrowerCashPost == borrowerCashPre) && + (borrowerBorrowsPost == borrowerBorrowsPre - repayAmount) && + (borrowerTokensPost == borrowerTokensPre) && + (otherCashPost == otherCashPre) && + (otherBorrowsPost == otherBorrowsPre) && + (otherTokensPost == otherTokensPre) && + (borrowerCollateralCashPost == borrowerCollateralCashPre) && + + (collateralExchangeRatePost == collateralExchangeRatePre) && + (collateralCashPost == collateralCashPre) && + (collateralBorrowsPost == collateralBorrowsPre) && + (collateralTokensPost == collateralTokensPre) && + (collateralReservesPost == collateralReservesPre) && + (liquidatorCollateralCashPost == liquidatorCollateralCashPre) && + (liquidatorCollateralBorrowsPost == liquidatorCollateralBorrowsPre) && + (liquidatorCollateralTokensPost - liquidatorCollateralTokensPre == borrowerCollateralTokensPre - borrowerCollateralTokensPost) && + (borrowerCollateralCashPost == borrowerCollateralCashPre) && + (borrowerCollateralBorrowsPost == borrowerCollateralBorrowsPre) && + (otherCollateralCashPost == otherCollateralCashPre) && + (otherCollateralBorrowsPost == otherCollateralBorrowsPre) && + (otherCollateralTokensPost == otherCollateralTokensPre); + + + static_assert (!liquidateBorrowFreshReverted => + ((result != 0 || repayAmount == 0 || liquidator == borrower) <=> staticBalance)), "Mismatch in static case"; + static_assert (!liquidateBorrowFreshReverted => + ((result == 0 && repayAmount != 0 && liquidator != currentContract) <=> dynamicBalance)), "Mismatch in dynamic case"; +} + +seize(uint result, address liquidator, address borrower, uint256 seizeTokens) +description "Break seize" { + // Pre/action/post environments + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + // Any other account + address other; havoc other; + static_require other != liquidator && other != borrower && other != currentContract; + + /* + - no effect on exchange rate + |----------+--------+------------+----------+-------| + | | CToken | Liquidator | Borrower | Other | + |----------+--------+------------+----------+-------| + | cash | 0 | 0 | 0 | 0 | + | borrows | 0 | 0 | 0 | 0 | + | tokens | 0 | +T | -T | 0 | + | reserves | 0 | | | | + |----------+--------+------------+----------+-------| + */ + + /* Pre */ + + uint256 exchangeRatePre = sinvoke exchangeRateStored(e0); + + uint256 cTokenCashPre = sinvoke getCash(e0); + uint256 liquidatorCashPre = sinvoke getCashOf(e0, liquidator); + uint256 borrowerCashPre = sinvoke getCashOf(e0, borrower); + uint256 otherCashPre = sinvoke getCashOf(e0, other); + + uint256 cTokenBorrowsPre = sinvoke totalBorrows(e0); + uint256 liquidatorBorrowsPre = sinvoke borrowBalanceStored(e0, liquidator); + uint256 borrowerBorrowsPre = sinvoke borrowBalanceStored(e0, borrower); + uint256 otherBorrowsPre = sinvoke borrowBalanceStored(e0, other); + + uint256 cTokenTokensPre = sinvoke totalSupply(e0); + uint256 liquidatorTokensPre = sinvoke balanceOf(e0, liquidator); + uint256 borrowerTokensPre = sinvoke balanceOf(e0, borrower); + uint256 otherTokensPre = sinvoke balanceOf(e0, other); + + uint256 cTokenReservesPre = sinvoke totalReserves(e0); + + // Just Do It + static_require result == invoke seize(e1, liquidator, borrower, seizeTokens); + bool seizeReverted = lastReverted; + + /* Post */ + + uint256 exchangeRatePost = sinvoke exchangeRateStored(e2); + + uint256 cTokenCashPost = sinvoke getCash(e2); + uint256 liquidatorCashPost = sinvoke getCashOf(e2, liquidator); + uint256 borrowerCashPost = sinvoke getCashOf(e2, borrower); + uint256 otherCashPost = sinvoke getCashOf(e2, other); + + uint256 cTokenBorrowsPost = sinvoke totalBorrows(e2); + uint256 liquidatorBorrowsPost = sinvoke borrowBalanceStored(e2, liquidator); + uint256 borrowerBorrowsPost = sinvoke borrowBalanceStored(e2, borrower); + uint256 otherBorrowsPost = sinvoke borrowBalanceStored(e2, other); + + uint256 cTokenTokensPost = sinvoke totalSupply(e2); + uint256 liquidatorTokensPost = sinvoke balanceOf(e2, liquidator); + uint256 borrowerTokensPost = sinvoke balanceOf(e2, borrower); + uint256 otherTokensPost = sinvoke balanceOf(e2, other); + + uint256 cTokenReservesPost = sinvoke totalReserves(e2); + + // Measure + bool staticBalance = + (exchangeRatePost == exchangeRatePre) && + (cTokenCashPost == cTokenCashPre) && + (cTokenBorrowsPost == cTokenBorrowsPre) && + (cTokenTokensPost == cTokenTokensPre) && + (cTokenReservesPost == cTokenReservesPre) && + (liquidatorCashPost == liquidatorCashPre) && + (liquidatorBorrowsPost == liquidatorBorrowsPre) && + (liquidatorTokensPost == liquidatorTokensPre) && + (borrowerCashPost == borrowerCashPre) && + (borrowerBorrowsPost == borrowerBorrowsPre) && + (borrowerTokensPost == borrowerTokensPre) && + (otherCashPost == otherCashPre) && + (otherBorrowsPost == otherBorrowsPre) && + (otherTokensPost == otherTokensPre); + + bool dynamicBalance = + (seizeTokens != 0) && + (exchangeRatePost == exchangeRatePre) && + (cTokenCashPost == cTokenCashPre) && + (cTokenBorrowsPost == cTokenBorrowsPre) && + (cTokenTokensPost == cTokenTokensPre) && + (cTokenReservesPost == cTokenReservesPre) && + (liquidatorCashPost == liquidatorCashPre) && + (liquidatorBorrowsPost == liquidatorBorrowsPre) && + (liquidatorTokensPost == liquidatorTokensPre + seizeTokens) && + (borrowerCashPost == borrowerCashPre) && + (borrowerBorrowsPost == borrowerBorrowsPre) && + (borrowerTokensPost == borrowerTokensPre - seizeTokens) && + (otherCashPost == otherCashPre) && + (otherBorrowsPost == otherBorrowsPre) && + (otherTokensPost == otherTokensPre); + + static_assert (!seizeReverted => + ((result != 0 || seizeTokens == 0 || liquidator == borrower) <=> staticBalance)), "Mismatch in static case"; + static_assert (!seizeReverted => + ((result == 0 && seizeTokens != 0) <=> dynamicBalance)), "Mismatch in dynamic case"; +} \ No newline at end of file diff --git a/spec/formal/maximillion.cvl b/spec/formal/maximillion.cvl new file mode 100644 index 000000000..933d614ec --- /dev/null +++ b/spec/formal/maximillion.cvl @@ -0,0 +1,33 @@ +methods { + borrowBalance(address) returns uint256 + etherBalance(address) returns uint256 + + repayBehalf(address) returns uint256 +} + +repayBehalf(uint256 repayAmount, address borrower) +description "Break repayBehalf" { + env e0; havoc e0; + env e1; havoc e1; + env e2; havoc e2; + + static_require e1.block.number == e0.block.number; + static_require e2.block.number >= e1.block.number; + + static_require e0.msg.value == 0; + uint256 borrowed = sinvoke borrowBalance(e0, borrower); + + static_require repayAmount == e1.msg.value; + invoke repayBehalf(e1, borrower); + bool repayReverted = lastReverted; + + static_require e2.msg.value == 0; + uint256 borrows = sinvoke borrowBalance(e2, borrower); + uint256 balance = sinvoke etherBalance(e2, e1.msg.sender); + + static_assert (!repayReverted => + ((repayAmount >= borrowed) => (balance >= repayAmount - borrowed))), "Mismatch in refund"; + static_assert (!repayReverted => + ((repayAmount >= borrowed) => (borrows == 0)) && + ((repayAmount < borrowed) => (borrows == borrowed - repayAmount))), "Mismatch in borrows repaid"; +} \ No newline at end of file diff --git a/spec/formal/mintAndRedeemFresh.cvl b/spec/formal/mintAndRedeemFresh.cvl new file mode 100644 index 000000000..379bcd70c --- /dev/null +++ b/spec/formal/mintAndRedeemFresh.cvl @@ -0,0 +1,447 @@ +methods { + admin() returns address + totalSupply() returns uint256 + balanceOf(address) returns uint256 + accrualBlockNumber() returns uint256 + initialExchangeRateMantissa() returns uint256 + totalBorrows() returns uint256 + totalReserves() returns uint256 + + // Exposing internal functions + mintFreshPub(address,uint256) returns uint256 + redeemFreshPub(address,uint256,uint256) returns uint256 + + exchangeRateStoredInternalPub() returns uint256, uint256 + checkTransferInPub(address,uint256) returns uint256 + doTransferInPub(address,uint256) returns uint256 + getCash() returns uint256 + comptrollerMintAllowed(address,address,uint256) returns uint256 + comptrollerRedeemAllowed(address,address,uint256) returns uint256 + + // Simulation of functions that have effects on external contracts + doTransferInPubSim(address,uint256) returns uint256 + doTransferOutPubSim(address,uint256) returns uint256 + + // Lemmas + cTokenMintComputation(uint256) returns uint256 + cTokenRedeemComputation(uint256) returns uint256 +} + +mintFresh(uint result, address account, uint256 amount) +description "Failed to mint fresh asset with result $result (minter account=$account, amount=$amount)" { + + // Free Variables + env e0; havoc e0; // pre + env e1; havoc e1; // invocation + env e1b; havoc e1b; // invocations on behalf of CToken + env e2; havoc e2; // post + + // Strict ordering + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + // Capture current values + uint256 totalSupplyPre = sinvoke totalSupply(e0); + uint256 accountSupplyPre = sinvoke balanceOf(e0, account); + uint256 marketBlockNumber = sinvoke accrualBlockNumber(e0); + + // Simulate checks that depend on external contracts + uint comptrollerCheckResult = sinvoke comptrollerMintAllowed(e1, currentContract,account,amount); + uint labelCheckTransferIn = sinvoke checkTransferInPub(e1b, account, amount); + uint labelDoTransferIn = sinvoke doTransferInPubSim(e1, account, amount); // SG: make sure doTransferInPubSim and doTransferIn return the same value when starting from the same state, and make sure dummy can simulate all observable external behaviors of the call. + + // Invoke mintFresh + static_require result == invoke mintFreshPub(e1, account, amount); + bool mintFreshReverted = lastReverted; + + // Get next values + uint256 totalSupplyPost = sinvoke totalSupply(e2); + uint256 accountSupplyPost = sinvoke balanceOf(e2, account); + + // Helper for checking balance has not changed + bool staticBalance = + ( totalSupplyPost == totalSupplyPre && + accountSupplyPost == accountSupplyPre ); + + // Helper for checking balance has not changed, as expected. + // Precise change is computed in cTokenComputationLemma + bool dynamicBalance = (totalSupplyPost - totalSupplyPre == accountSupplyPost - accountSupplyPre) // Change in totalSupply is same as change in accountSupply + && (totalSupplyPost - totalSupplyPre >= 0); // The change in supplies must be >= 0 + + bool comptrollerCheckSuccess = comptrollerCheckResult == 0; + bool accrued = marketBlockNumber == e1.block.number; + bool checkTransferSuccess = labelCheckTransferIn == 0; + bool doTransferSuccess = labelDoTransferIn == 0; + + // Track error codes + uint256 NO_ERROR = 0; + uint256 COMPTROLLER_REJECTION = 3; + uint256 NOT_ACCRUED = 10; + uint256 CHECK_TRANSFER_FAILED_1 = 12; + uint256 CHECK_TRANSFER_FAILED_2 = 13; + uint256 TOKEN_TRANSFER_IN_FAILED = 15; + uint256 MATH_ERROR = 9; + + // Guarantee return values + static_assert (!mintFreshReverted && result != MATH_ERROR) => ( + result == NO_ERROR || + result == COMPTROLLER_REJECTION || + result == NOT_ACCRUED || + result == CHECK_TRANSFER_FAILED_1 || + result == CHECK_TRANSFER_FAILED_2 || + result == TOKEN_TRANSFER_IN_FAILED || + result == MATH_ERROR + ), "Got unexpected error code $result"; + + /* All these cases depend on: (1) mintFresh not reverting; and (2) the error code being anything other than a math error. + The idea is that (1) reverts, if are not catched by the caller (could it be a contract by Compound?), will have no effect on the state; + and (2) math errors, which are handled separately. + */ + // Success case updates market accordingly + static_assert (!mintFreshReverted && result != MATH_ERROR) => (result == NO_ERROR <=> ( + comptrollerCheckSuccess && + accrued && + checkTransferSuccess && + doTransferSuccess && + dynamicBalance + )), "Mismatch in no error case (0). Got result $result"; + + // Policy hook rejected case + static_assert (!mintFreshReverted && result != MATH_ERROR) => (result == COMPTROLLER_REJECTION <=> ( + !comptrollerCheckSuccess && + staticBalance + )), "Mismatch in comptroller rejection case (3). Got result $result"; + + // Not accrued + static_assert (!mintFreshReverted && result != MATH_ERROR) => (result == NOT_ACCRUED <=> ( + comptrollerCheckSuccess && + !accrued && + staticBalance + )), "Mismatch in non-accrued case (10=0xa). Got result $result"; + + // Check transfer failure + static_assert (!mintFreshReverted && result != MATH_ERROR) => ((result == CHECK_TRANSFER_FAILED_1 || result == CHECK_TRANSFER_FAILED_2) <=> ( + comptrollerCheckSuccess && + accrued && + !checkTransferSuccess && + staticBalance + )), "Mismatch in check transfer failure (12,13). Got result $result"; + + // TODO: SG: I think Geoff said a revert was the intention! + // Do transfer failure + static_assert (!mintFreshReverted && result != MATH_ERROR) => (result == TOKEN_TRANSFER_IN_FAILED <=> + ( + comptrollerCheckSuccess && + accrued && + checkTransferSuccess && + !doTransferSuccess && + staticBalance + )), "Mismatch in do transfer failure (15). Got result $result"; + + // Math error -> no state changes (at least, the ones we observe here! This is not checking about the FULL state of the contract) + // SG: Idea - this could be a useful check that is reused across many of Compound's functions that may return math error codes, and will be more thorough. + static_assert !mintFreshReverted => (result == MATH_ERROR => + ( + staticBalance + )), "State changes occuring despite math error, totalSupplyPre=$totalSupplyPre, totalSupplyPost=$totalSupplyPost ; accountSupplyPre=$accountSupplyPre, accountSupplyPost=$accountSupplyPost"; +} + +mintFresh_extended(uint result, address account, uint256 amount) +description "Failed to mint fresh asset with result $result (account=$account, amount=$amount)" { + // Free Variables + env e0; havoc e0; // pre + env e1; havoc e1; // invocation + env e2; havoc e2; // post + + // Strict ordering + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + // Minting to self is assumed to be impossible + static_require account != currentContract; + + // Capture current values + uint256 totalSupplyPre = sinvoke totalSupply(e0); + uint256 accountSupplyPre = sinvoke balanceOf(e0, account); + uint256 marketBlockNumber = sinvoke accrualBlockNumber(e0); + + uint256 cash = sinvoke getCash(e0); + + // Label CALL results + uint comptrollerCheckResult = sinvoke comptrollerMintAllowed(e1, currentContract, account, amount); + uint labelCheckTransferIn = sinvoke checkTransferInPub(e1, account, amount); + uint labelDoTransferIn = sinvoke doTransferInPubSim(e1, account, amount); + + // Invoke mintFresh + static_require result == invoke mintFreshPub(e1, account, amount); + bool mintFreshReverted = lastReverted; + + // Get next values + uint256 totalSupplyPost = sinvoke totalSupply(e2); + uint256 accountSupplyPost = sinvoke balanceOf(e2, account); + uint256 newCash = sinvoke getCash(e2); + + // Helper for checking balance has not changed + bool staticBalance = + ( totalSupplyPost == totalSupplyPre && + accountSupplyPost == accountSupplyPre ) + && cash == newCash ; + + // Helper for checking balance has not changed, as expected. + // Precise change is computed in cTokenComputationLemma + bool dynamicBalance = (totalSupplyPost - totalSupplyPre == accountSupplyPost - accountSupplyPre) // Change in totalSupply is same as change in accountSupply + && (totalSupplyPost - totalSupplyPre >= 0) // The change in supplies must be >= 0 + && (newCash - cash == amount); // The change in cash must be amount + + bool comptrollerCheckSuccess = comptrollerCheckResult == 0; // Comptroller is an external contract and its error is converted to COMPTROLLER_REJECTION, so no need to require on the label + bool accrued = marketBlockNumber == e1.block.number; + bool checkTransferSuccess = labelCheckTransferIn == 0; + bool doTransferSuccess = labelDoTransferIn == 0; + + // Track error codes + uint256 NO_ERROR = 0; + uint256 COMPTROLLER_REJECTION = 3; + uint256 NOT_ACCRUED = 10; + uint256 CHECK_TRANSFER_FAILED_1 = 12; + uint256 CHECK_TRANSFER_FAILED_2 = 13; + uint256 TOKEN_TRANSFER_IN_FAILED = 15; + uint256 MATH_ERROR = 9; + + // Guarantee return values + static_assert (!mintFreshReverted && result != MATH_ERROR) => ( + result == NO_ERROR || + result == COMPTROLLER_REJECTION || + result == NOT_ACCRUED || + result == CHECK_TRANSFER_FAILED_1 || + result == CHECK_TRANSFER_FAILED_2 || + result == TOKEN_TRANSFER_IN_FAILED || + result == MATH_ERROR + ), "Got unexpected error code $result"; + + /* All these cases depend on: (1) mintFresh not reverting; and (2) the error code being anything other than a math error. + The idea is that (1) reverts, if are not catched by the caller (could it be a contract by Compound?), will have no effect on the state; + and (2) math errors, which are handled separately. + */ + // Success case updates market accordingly + static_assert (!mintFreshReverted && result != MATH_ERROR) => (result == NO_ERROR <=> ( + comptrollerCheckSuccess && + accrued && + checkTransferSuccess && + doTransferSuccess && + dynamicBalance + )), "Mismatch in no error case (0). Got result $result"; + + // Policy hook rejected case + static_assert (!mintFreshReverted && result != MATH_ERROR) => (result == COMPTROLLER_REJECTION <=> ( + !comptrollerCheckSuccess && + staticBalance + )), "Mismatch in comptroller rejection case (3). Got result $result"; + + // Not accrued + static_assert (!mintFreshReverted && result != MATH_ERROR) => (result == NOT_ACCRUED <=> ( + comptrollerCheckSuccess && + !accrued && + staticBalance + )), "Mismatch in non-accrued case (10=0xa). Got result $result"; + + // Check transfer failure + static_assert (!mintFreshReverted && result != MATH_ERROR) => ((result == CHECK_TRANSFER_FAILED_1 || result == CHECK_TRANSFER_FAILED_2) <=> ( + comptrollerCheckSuccess && + accrued && + !checkTransferSuccess && + staticBalance + )), "Mismatch in check transfer failure (12,13). Got result $result"; + + // Do transfer failure + static_assert (!mintFreshReverted && result != MATH_ERROR) => (result == TOKEN_TRANSFER_IN_FAILED <=> + ( + comptrollerCheckSuccess && + accrued && + checkTransferSuccess && + !doTransferSuccess && + staticBalance + )), "Mismatch in do transfer failure (15). Got result $result"; + + // Math error -> no state changes (at least, the ones we observe here! This is not checking about the FULL state of the contract) + // SG: Idea - this could be a useful check that is reused across many of Compound's functions that may return math error codes, and will be more thorough. + static_assert !mintFreshReverted => (result == MATH_ERROR => + ( + staticBalance + )), "State changes occuring despite math error, totalSupplyPre=$totalSupplyPre, totalSupplyPost=$totalSupplyPost ; accountSupplyPre=$accountSupplyPre, accountSupplyPost=$accountSupplyPost"; +} + + +redeemFresh(uint result, address account, uint256 amountCTokens, uint256 amountUnderlying) +description "Failed to redeemFresh fresh asset with result $result (account=$account, amountCTokens=$amountCTokens, amountUnderlying=$amountUnderlying)" { + // Free Variables + env e0; havoc e0; // pre + env e1; havoc e1; // invocation + env e1b; havoc e1b; // invocations on behalf of CToken + env e2; havoc e2; // post + + // Strict ordering + static_require e1.block.number >= e0.block.number; + static_require e2.block.number >= e1.block.number; + + // Redeeming from self is assumed to be impossible + static_require account != currentContract; + + // Capture current values + uint256 totalSupplyPre = sinvoke totalSupply(e0); + uint256 accountSupplyPre = sinvoke balanceOf(e0, account); + uint256 marketBlockNumber = sinvoke accrualBlockNumber(e0); + uint256 cash = sinvoke getCash(e0); + + // Simulate checks that depend on external contracts + uint comptrollerCheckResult = sinvoke comptrollerRedeemAllowed(e1, currentContract, account, amountCTokens); // Should include amountUnderlying? + uint labelDoTransferOut = sinvoke doTransferOutPubSim(e1, account, amountUnderlying); + + // Invoke mintFresh + static_require result == invoke redeemFreshPub(e1, account, amountCTokens, amountUnderlying); + bool redeemFreshReverted = lastReverted; + + // Get next values + uint256 totalSupplyPost = sinvoke totalSupply(e2); + uint256 accountSupplyPost = sinvoke balanceOf(e2, account); + uint256 newCash = sinvoke getCash(e2); + + // Helper for checking balance has not changed + bool staticBalance = + ( totalSupplyPost == totalSupplyPre && + accountSupplyPost == accountSupplyPre ) + && cash == newCash ; + + // Helper for checking balance has not changed, as expected. + // Precise change is computed in cTokenComputationLemma + bool dynamicBalanceBasic = (totalSupplyPre - totalSupplyPost == accountSupplyPre - accountSupplyPost) // Change in totalSupply is same as change in accountSupply + && (totalSupplyPre - totalSupplyPost >= 0) // The change in supplies must be <= 0 + && (cash - newCash >= 0); // This operation transfers out + bool dynamicBalanceRedeemingUnderlying = (cash - newCash == amountUnderlying); // The change in cash must be amount + bool dynamicBalanceRedeemingCToken = (totalSupplyPre-totalSupplyPost == amountCTokens); // The change in CToken must be -amountCTokens + bool dynamicBalanceAdvanced = ((amountCTokens > 0 && amountUnderlying == 0) => dynamicBalanceRedeemingCToken) + && ((amountCTokens == 0 && amountUnderlying > 0) => dynamicBalanceRedeemingUnderlying) + && ((amountCTokens == 0 && amountUnderlying == 0) => (dynamicBalanceRedeemingCToken && dynamicBalanceRedeemingUnderlying)) + && !(amountCTokens > 0 && amountUnderlying > 0); + + bool comptrollerCheckSuccess = comptrollerCheckResult == 0; + bool accrued = marketBlockNumber == e1.block.number; + bool checkTransferSuccess = cash >= amountUnderlying; + bool doTransferSuccess = labelDoTransferOut == 0; + + // Track error codes + uint256 NO_ERROR = 0; + uint256 COMPTROLLER_REJECTION = 3; + uint256 NOT_ACCRUED = 10; + uint256 CHECK_TRANSFER_FAILED = 14; // TOKEN_INSUFFICIENT_CASH + uint256 TOKEN_TRANSFER_OUT_FAILED = 16; + uint256 MATH_ERROR = 9; + + // Guarantee return values + static_assert (!redeemFreshReverted && result != MATH_ERROR) => ( + result == NO_ERROR || + result == COMPTROLLER_REJECTION || + result == NOT_ACCRUED || + result == CHECK_TRANSFER_FAILED || + result == TOKEN_TRANSFER_OUT_FAILED || + result == MATH_ERROR + ), "Got unexpected error code $result"; + + + // Success case updates market accordingly + static_assert (!redeemFreshReverted && result != MATH_ERROR) => (result == NO_ERROR <=> ( + comptrollerCheckSuccess && + accrued && + checkTransferSuccess && + doTransferSuccess && + dynamicBalanceBasic && + dynamicBalanceAdvanced + )), "Mismatch in no error case (0). Got result $result"; + + // Policy hook rejected case + static_assert (!redeemFreshReverted && result != MATH_ERROR) => (result == COMPTROLLER_REJECTION <=> ( + !comptrollerCheckSuccess && + staticBalance + )), "Mismatch in comptroller rejection case (3=0x3). Got result $result"; + + // Not accrued + static_assert (!redeemFreshReverted && result != MATH_ERROR) => (result == NOT_ACCRUED <=> ( + comptrollerCheckSuccess && + !accrued && + staticBalance + )), "Mismatch in non-accrued case (10=0xa). Got result $result"; + + // Check transfer failure + // Note that since if amountUnderlying == 0 we do not compute in the spec the computed amountUnderlying, so we skip the test for now + static_assert (!redeemFreshReverted && result != MATH_ERROR && amountUnderlying > 0) => ((result == CHECK_TRANSFER_FAILED) <=> ( + comptrollerCheckSuccess && + accrued && + !checkTransferSuccess && + staticBalance + )), "Mismatch in check transfer failure (14). Got result $result"; + + // Do transfer failure + // Should be: static_assert !doTransferSuccess => redeemFreshReverted; + static_assert (!redeemFreshReverted && result != MATH_ERROR) => (result == TOKEN_TRANSFER_OUT_FAILED <=> + ( + comptrollerCheckSuccess && + accrued && + checkTransferSuccess && + !doTransferSuccess && + staticBalance + )), "Mismatch in do transfer failure (16). Got result $result"; + + // Math error -> no state changes (at least, the ones we observe here! This is not checking about the FULL state of the contract) + // SG: Idea - this could be a useful check that is reused across many of Compound's functions that may return math error codes, and will be more thorough. + static_assert !redeemFreshReverted => (result == MATH_ERROR => + ( + staticBalance && + newCash == cash + )), "State changes occuring despite math error, totalSupplyPre=$totalSupplyPre, totalSupplyPost=$totalSupplyPost ; accountSupplyPre=$accountSupplyPre, accountSupplyPost=$accountSupplyPost"; +} + +mintThenRedeem(address account, uint256 amountUnderlying) +description "Mint and redeem are not inverses for account $account, amount $amountUnderlying" +{ + env e0; havoc e0; + + uint origCash = sinvoke getCash(e0); + + // both calls are "fresh" + uint resultMint = invoke mintFreshPub(e0, account, amountUnderlying); + bool revertedMint = lastReverted; + + uint resultRedeem = invoke redeemFreshPub(e0, account, 0, amountUnderlying); + bool revertedRedeem = lastReverted; + + uint newCash = sinvoke getCash(e0); + + static_assert (resultMint == 0 && !revertedMint && resultRedeem == 0 && !revertedRedeem) => newCash == origCash; + + // check that exchange rate is the same, check all the 4 variables that affect the exchange rate are retained. + // check that accounts balances are the same. + // the only thing that changes is the interest index. rounding errors. +} + + +/* +ERRORS: + +0 NO_ERROR, +1 UNAUTHORIZED, +2 BAD_INPUT, +3 COMPTROLLER_REJECTION, +4 COMPTROLLER_CALCULATION_ERROR, +5 INTEREST_RATE_MODEL_ERROR, +6 INVALID_ACCOUNT_PAIR, +7 INVALID_CLOSE_AMOUNT_REQUESTED, +8 INVALID_COLLATERAL_FACTOR, +9 MATH_ERROR, +10 MARKET_NOT_FRESH, +11 MARKET_NOT_LISTED, +12 TOKEN_INSUFFICIENT_ALLOWANCE, +13 TOKEN_INSUFFICIENT_BALANCE, +14 TOKEN_INSUFFICIENT_CASH, +15 TOKEN_TRANSFER_IN_FAILED, +16 TOKEN_TRANSFER_OUT_FAILED + +*/ diff --git a/spec/scenario/Borrow.scen b/spec/scenario/Borrow.scen new file mode 100644 index 000000000..3790a73cf --- /dev/null +++ b/spec/scenario/Borrow.scen @@ -0,0 +1,46 @@ + +-- Waiting on Comptroller actually checking market entered +Test "Borrow some BAT fails when BAT not entered" + NewComptroller price:1.0 + NewCToken ZRX cZRX + NewCToken BAT cBAT + Support cZRX collateralFactor:0.5 + Support cBAT collateralFactor:0.5 + Prep Geoff Some ZRX cZRX + Mint Geoff 100e18 cZRX + EnterMarkets Geoff cZRX + Invariant Static (CToken cZRX ExchangeRateStored) + AllowFailures + Borrow Geoff 1e18 cBAT + Assert Failure COMPTROLLER_REJECTION BORROW_COMPTROLLER_REJECTION MARKET_NOT_ENTERED + +Test "Borrow some BAT fails when no BAT available" + NewComptroller price:1.0 + NewCToken ZRX cZRX + NewCToken BAT cBAT + Support cZRX collateralFactor:0.5 + Support cBAT collateralFactor:0.5 + Prep Geoff Some ZRX cZRX + Mint Geoff 100e18 cZRX + EnterMarkets Geoff cZRX cBAT + Invariant Static (CToken cZRX ExchangeRateStored) + AllowFailures + Borrow Geoff 1e18 cBAT + Assert Failure TOKEN_INSUFFICIENT_CASH BORROW_CASH_NOT_AVAILABLE + +Test "Borrow some BAT from Excess Cash" + Invariant Success + NewComptroller price:1.0 + NewCToken ZRX cZRX + NewCToken BAT cBAT + Give cBAT 10e18 BAT -- Faucet some bat to borrow + Support cZRX collateralFactor:0.5 + Support cBAT collateralFactor:0.5 + Prep Geoff Some ZRX cZRX + Mint Geoff 100e18 cZRX + EnterMarkets Geoff cZRX cBAT + Borrow Geoff 1e18 cBAT + EnterMarkets Geoff cZRX cBAT + Assert Equal (cToken cBAT BorrowBalance Geoff) (Exactly 1e18) + Assert Equal (Erc20 BAT TokenBalance Geoff) (Exactly 1e18) + Assert Equal (Erc20 BAT TokenBalance cBAT) (Exactly 9e18) diff --git a/spec/scenario/Borrow.scen.old b/spec/scenario/Borrow.scen.old new file mode 100644 index 000000000..e53c1619c --- /dev/null +++ b/spec/scenario/Borrow.scen.old @@ -0,0 +1,87 @@ +-- Borrow Tests + +Macro CreateSupportedAsset token price interestRate policyHook + AddToken token + SupportMarket token price interestRate policyHook + Assert Success + +Macro CreateSupply user token amount + Approve user token amount + Faucet user token amount + Supply user token amount + Assert Success + +Test "Supply Ether and Borrow OMG" + -- Note that borrow reduces Cash but does not reduce the Supply balance sheet. + CreateSupportedAsset Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + CreateSupply Geoff Ether 10.0e18 + Assert Equal (SupplyBalance Geoff Ether) (Exactly 10.0e18) + FastForward 2 Blocks + CreateSupportedAsset OMG (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + AddCash OMG 1e20 + CreateSupply Torrey OMG 5.0e18 + Assert Equal (BalanceSheetSupply OMG) (Exactly 5.0e18) + Assert Equal (TokenBalance Geoff OMG) (Exactly 0.0e18) + EnterMarkets Geoff OMG + Borrow Geoff OMG 2.0e18 + Assert Success + Assert Equal (BalanceSheetBorrow OMG) (Exactly 2.1e18) -- includes origination fee + Assert Equal (BorrowBalance Geoff OMG) (Exactly 2.1e18) -- includes origination fee + Assert Equal (TokenBalance Geoff OMG) (Exactly 2.0e18) -- does not include origination fee + -- + -- OMG total supply unchanged + Assert Equal (BalanceSheetSupply OMG) (Exactly 5.0e18) + + +Test "Supply Ether and attempt to Borrow more OMG than supported by collateral ratio" + -- Note that borrow reduces Cash but does not reduce the Supply balance sheet. + CreateSupportedAsset Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + CreateSupply Geoff Ether 3.0e18 + Assert Equal (SupplyBalance Geoff Ether) (Exactly 3.0e18) + Assert Equal (MaxBorrow Geoff) (Exactly 1.5e18) -- the original supply has doubled due to interest, so max borrow value has also doubled + FastForward 2 Blocks + CreateSupportedAsset OMG (FixedPrice 0.2) (FixedRate 0.5 0.75) SimplePolicyHook + AddCash OMG 1e20 + CreateSupply Torrey OMG 30.0e18 + Assert Equal (BalanceSheetSupply OMG) (Exactly 30.0e18) + Assert Equal (TokenBalance Geoff OMG) (Exactly 0.0e18) + Assert Equal (MaxBorrow Geoff) (Exactly 3.0e18) -- the original supply has doubled due to interest, so max borrow value has also doubled + EnterMarkets Geoff OMG + Borrow Geoff OMG 20.0e18 + Assert Failure INSUFFICIENT_LIQUIDITY BORROW_AMOUNT_LIQUIDITY_SHORTFALL + Assert Equal (BorrowBalance Geoff OMG) (Exactly 0.0e18) + Assert Equal (TokenBalance Geoff OMG) (Exactly 0.0e18) + Assert Equal (BalanceSheetBorrow OMG) (Exactly 0.0e18) + -- + -- OMG total supply unchanged + Assert Equal (BalanceSheetSupply OMG) (Exactly 30.0e18) + +Test "Can't borrow an initial state asset" + CreateSupportedAsset Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + CreateSupply Geoff Ether 30.0e18 + FastForward 2 Blocks + AddToken OMG + AddCash OMG 1e20 + Borrow Geoff OMG 1e18 + Assert Failure MARKET_NOT_LISTED BORROW_MARKET_NOT_LISTED + +Test "Can't borrow when contract is paused" + CreateSupportedAsset Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + CreateSupply Geoff Ether 10.0e18 + Assert Equal (SupplyBalance Geoff Ether) (Exactly "10.0e18") + FastForward 2 Blocks + CreateSupportedAsset OMG (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + CreateSupply Torrey OMG 5.0e18 + AddCash OMG 1e20 + Assert Equal (BalanceSheetSupply OMG) (Exactly 5.0e18) + Assert Equal (TokenBalance Geoff OMG) (Exactly 0.0e18) + PolicyHook OMG (SetPaused True) + Borrow Geoff OMG 2.0e18 + Assert Failure COMPTROLLER_REJECTION BORROW_COMPTROLLER_REJECTION 1 + Assert Equal (BorrowBalance Geoff OMG) (Exactly 0.0e18) + Assert Equal (TokenBalance Geoff OMG) (Exactly 0.0e18) + +Test "Can't borrow if have not entered market" + CreateSupportedAsset OMG (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Borrow Geoff OMG 2.0e18 + Assert Failure ASSET_NOT_ENTERED BORROW_ASSET_NOT_ENTERED diff --git a/spec/scenario/BorrowBalance.scen b/spec/scenario/BorrowBalance.scen new file mode 100644 index 000000000..312f8a748 --- /dev/null +++ b/spec/scenario/BorrowBalance.scen @@ -0,0 +1,84 @@ +-- Tests for the current borrow balance in a number of scenarios + +Macro NewBorrow borrowAmount borrowRate user=Geoff + NewComptroller price:1.0 -- TODO: This should really be a price for a specific asset + NewCToken ZRX cZRX + NewCToken BAT cBAT borrowRate -- note: cannot use macros with named args right now + Give cBAT 10e18 BAT -- Faucet some bat to borrow + Support cZRX collateralFactor:0.5 + Support cBAT collateralFactor:0.5 + SimpleBorrow user borrowAmount + +Macro SimpleBorrow user borrowAmount + Prep user Some ZRX cZRX + Mint user 100e18 cZRX + EnterMarkets user cZRX cBAT + Borrow user borrowAmount cBAT + +Test "Borrow Balance after 3000 blocks" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (cToken cBAT BorrowBalance Geoff) (Exactly 1e18) + Assert Equal (cToken cBAT TotalBorrowsCurrent) (Exactly 1e18) + Assert Equal (Erc20 BAT TokenBalance Geoff) (Exactly 1e18) + Assert Equal (Erc20 BAT TokenBalance cBAT) (Exactly 9e18) + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 1e18 * (1 + 3000 * 0.0005) + Assert Equal (cToken cBAT BorrowBalance Geoff) (Exactly 2.5e18) + Assert Equal (cToken cBAT TotalBorrowsCurrent) (Exactly 2.5e18) + +Test "Borrow Balance after 3000 blocks and then 6000 blocks" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (cToken cBAT BorrowBalance Geoff) (Exactly 1e18) + Assert Equal (cToken cBAT TotalBorrowsCurrent) (Exactly 1e18) + Assert Equal (Erc20 BAT TokenBalance Geoff) (Exactly 1e18) + Assert Equal (Erc20 BAT TokenBalance cBAT) (Exactly 9e18) + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 1e18 * (1 + 3000 * 0.0005) + AccrueInterest cBAT + Assert Equal (cToken cBAT BorrowBalance Geoff) (Exactly 2.5e18) + Assert Equal (cToken cBAT TotalBorrowsCurrent) (Exactly 2.5e18) + FastForward 6000 Blocks -- 1e18 * (1 + 3000 * 0.0005) * (1 + 6000 * 0.0005) + Assert Equal (cToken cBAT BorrowBalance Geoff) (Exactly 10e18) + Assert Equal (cToken cBAT TotalBorrowsCurrent) (Exactly 10e18) + +Test "Borrow Balance after accrual then changed interest rate" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (cToken cBAT BorrowBalance Geoff) (Exactly 1e18) + Assert Equal (cToken cBAT TotalBorrowsCurrent) (Exactly 1e18) + Assert Equal (Erc20 BAT TokenBalance Geoff) (Exactly 1e18) + Assert Equal (Erc20 BAT TokenBalance cBAT) (Exactly 9e18) + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- Current: 1e18 * (1 + 3000 * 0.0005) + -- Note: this should accrue interest + InterestRateModel Deploy Fixed Std 0.0004 + CToken cBAT SetInterestRateModel (InterestRateModel Std Address) + -- Check borrow balance still based on old figure (with previous interest accrual) + Assert Equal (cToken cBAT BorrowBalance Geoff) (Exactly 2.5e18) + Assert Equal (cToken cBAT TotalBorrowsCurrent) (Exactly 2.5e18) + -- Now accrue with new rate + FastForward 8000 Blocks -- 1e18 * (1 + 3000 * 0.0005) * (1 + 8000 * 0.0004) + Assert Equal (cToken cBAT BorrowBalance Geoff) (Exactly 10.5e18) + Assert Equal (cToken cBAT TotalBorrowsCurrent) (Exactly 10.5e18) + +Test "Total Borrow Balance with Two Borrowers" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 user:Geoff + FastForward 3000 Blocks + InterestRateModel Deploy Fixed Std 0.0004 + CToken cBAT SetInterestRateModel (InterestRateModel Std Address) + -- Check borrow balance still based on old figure (with previous interest accrual) + Assert Equal (cToken cBAT BorrowBalance Geoff) (Exactly 2.5e18) + Assert Equal (cToken cBAT TotalBorrowsCurrent) (Exactly 2.5e18) + SimpleBorrow user:Torrey borrowAmount:5e18 + -- Now accrue with new rate + FastForward 8000 Blocks + -- Geoff: 1e18 * (1 + 3000 * 0.0005) * (1 + 8000 * 0.0004) + Assert Equal (cToken cBAT BorrowBalance Geoff) (Exactly 10.5e18) + -- Torrey: 5e18 * (1 + 8000 * 0.0004) + Assert Equal (cToken cBAT BorrowBalance Torrey) (Exactly 21e18) + Assert Equal (cToken cBAT TotalBorrowsCurrent) (Exactly 31.5e18) + -- And test some repayment + From Torrey (Erc20 BAT Approve cBAT 2.0e18) + RepayBorrow Torrey 2.0e18 cBAT + Assert Equal (cToken cBAT BorrowBalance Geoff) (Exactly 10.5e18) + Assert Equal (cToken cBAT BorrowBalance Torrey) (Exactly 19e18) + Assert Equal (cToken cBAT TotalBorrowsCurrent) (Exactly 29.5e18) diff --git a/spec/scenario/BorrowEth.scen b/spec/scenario/BorrowEth.scen new file mode 100644 index 000000000..83ba4d5b5 --- /dev/null +++ b/spec/scenario/BorrowEth.scen @@ -0,0 +1,49 @@ + +Test "Borrow some Eth fails when Eth not entered" + NewComptroller price:1.0 + ListedCToken ZRX cZRX + ListedEtherToken cETH initialExchangeRate:0.005e9 + SetCollateralFactor cZRX collateralFactor:0.5 + SetCollateralFactor cETH collateralFactor:0.5 + Prep Geoff Some ZRX cZRX + Mint Geoff 100e18 cZRX + EnterMarkets Geoff cZRX + AllowFailures + Invariant Static (CToken cZRX ExchangeRateStored) + Invariant Static (CToken cETH ExchangeRateStored) + Invariant Static (Comptroller Liquidity Geoff) + Invariant Static (EtherBalance Geoff) + BorrowEth Geoff 1e18 cETH + Assert Failure COMPTROLLER_REJECTION BORROW_COMPTROLLER_REJECTION MARKET_NOT_ENTERED + +Test "Borrow some ETH fails when no ETH available" + NewComptroller price:1.0 + ListedCToken ZRX cZRX + ListedEtherToken cETH initialExchangeRate:0.005e9 + SetCollateralFactor cZRX collateralFactor:0.5 + SetCollateralFactor cETH collateralFactor:0.5 + Prep Geoff Some ZRX cZRX + Mint Geoff 100e18 cZRX + EnterMarkets Geoff cZRX cETH + AllowFailures + Invariant Static (CToken cZRX ExchangeRateStored) + Invariant Static (CToken cETH ExchangeRateStored) + Invariant Static (Comptroller Liquidity Geoff) + Invariant Static (EtherBalance Geoff) + BorrowEth Geoff 1e18 cETH + Assert Failure TOKEN_INSUFFICIENT_CASH BORROW_CASH_NOT_AVAILABLE + +Test "Borrow some ETH from excess cash" + NewComptroller price:1.0 + ListedCToken ZRX cZRX + ListedEtherToken cETH initialExchangeRate:0.005e9 + SetCollateralFactor cZRX collateralFactor:0.5 + SetCollateralFactor cETH collateralFactor:0.5 + Donate cETH 0.003e18 + Prep Geoff Some ZRX cZRX + Mint Geoff 1e18 cZRX + EnterMarkets Geoff cZRX cETH + Expect Changes (EtherBalance Geoff) +0.001e18 + BorrowEth Geoff 0.001e18 cETH + Assert Equal (EtherBalance cETH) 0.002e18 + Assert Equal (Comptroller Liquidity Geoff) 4.99e17 diff --git a/spec/scenario/BorrowWBTC.scen b/spec/scenario/BorrowWBTC.scen new file mode 100644 index 000000000..5607efd97 --- /dev/null +++ b/spec/scenario/BorrowWBTC.scen @@ -0,0 +1,62 @@ + +-- Waiting on Comptroller actually checking market entered +Test "Borrow some WBTC fails when WBTC not entered" + NewComptroller price:1.0 + NewCToken ZRX cZRX + NewCToken WBTC cWBTC tokenType:WBTC + Support cZRX collateralFactor:0.5 + Support cWBTC collateralFactor:0.5 + Prep Geoff Some ZRX cZRX + Mint Geoff 100e18 cZRX + EnterMarkets Geoff cZRX + Invariant Static (CToken cZRX ExchangeRateStored) + AllowFailures + Borrow Geoff 1e8 cWBTC + Assert Failure COMPTROLLER_REJECTION BORROW_COMPTROLLER_REJECTION MARKET_NOT_ENTERED + +Test "Borrow some WBTC fails when no WBTC available" + NewComptroller price:1.0 + NewCToken ZRX cZRX + NewCToken WBTC cWBTC tokenType:WBTC + Support cZRX collateralFactor:0.5 + Support cWBTC collateralFactor:0.5 + Prep Geoff Some ZRX cZRX + Mint Geoff 100e18 cZRX + EnterMarkets Geoff cZRX cWBTC + Invariant Static (CToken cZRX ExchangeRateStored) + AllowFailures + Borrow Geoff 1e8 cWBTC + Assert Failure TOKEN_INSUFFICIENT_CASH BORROW_CASH_NOT_AVAILABLE + +Test "Borrow some WBTC fails when WBTC paused" + NewComptroller price:1.0 + NewCToken ZRX cZRX + NewCToken WBTC cWBTC tokenType:WBTC + Give cWBTC 10e8 WBTC -- Faucet some WBTC to borrow + Support cZRX collateralFactor:0.5 + Support cWBTC collateralFactor:0.5 + Prep Geoff Some ZRX cZRX + Mint Geoff 100e18 cZRX + EnterMarkets Geoff cZRX cWBTC + Invariant Static (CToken cZRX ExchangeRateStored) + Erc20 WBTC Pause + AllowFailures + Borrow Geoff 1e8 cWBTC + Assert Revert + +Test "Borrow some WBTC from Excess Cash" + Invariant Success + NewComptroller price:1.0 + NewCToken ZRX cZRX + NewCToken WBTC cWBTC tokenType:WBTC + Give cWBTC 10e8 WBTC -- Faucet some WBTC to borrow + Support cZRX collateralFactor:0.5 + Support cWBTC collateralFactor:0.5 + Prep Geoff Some ZRX cZRX + Mint Geoff 100e18 cZRX + EnterMarkets Geoff cZRX cWBTC + Borrow Geoff 1e8 cWBTC + EnterMarkets Geoff cZRX cWBTC + Assert Equal (cToken cWBTC BorrowBalance Geoff) (Exactly 1e8) + Assert Equal (Erc20 WBTC TokenBalance Geoff) (Exactly 1e8) + Assert Equal (Erc20 WBTC TokenBalance cWBTC) (Exactly 9e8) diff --git a/spec/scenario/BreakLiquidate.scen b/spec/scenario/BreakLiquidate.scen new file mode 100644 index 000000000..0990ef2ae --- /dev/null +++ b/spec/scenario/BreakLiquidate.scen @@ -0,0 +1,82 @@ + +Macro NewBorrow borrowAmount mintAmount borrowRate=0.0005 user=Geoff collateralPrice=1.0 borrowPrice=1.0 liquidationIncentive=1.1 + PricedComptroller closeFactor:0.9 -- Set the close factor high to reduce number of steps to demonstrate + Comptroller LiquidationIncentive liquidationIncentive + NewCToken ZRX cZRX + NewCToken BAT cBAT borrowRate + Give cBAT 10e18 BAT -- Faucet some bat to borrow + PriceOracle SetPrice cZRX collateralPrice + Support cZRX collateralFactor:0.7 + PriceOracle SetPrice cBAT borrowPrice + Support cBAT collateralFactor:0 + SimpleBorrow user borrowAmount mintAmount + +Macro SimpleBorrow user borrowAmount mintAmount + Prep user mintAmount ZRX cZRX + Mint user mintAmount cZRX + EnterMarkets user cZRX cBAT + Borrow user borrowAmount cBAT + +Test "When account goes further underwater than the liquidation incentive and cannot pay down debt fully" + -- Happens whenever collateral ratio > liquidation discount (i.e. 1 / liquidation incentive) + -- + -- Start right around the liquidity threshold + NewBorrow borrowAmount:1e18 mintAmount:1.43e18 liquidationIncentive:1.1 + -- + -- Verify that the borrow results in the correct state + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 1.43e18 + -- + -- Put the account underwater s.t. 0.91 < Borrow/Supply + -- i.e. (1 / liquidationIncentive) < Borrow/Supply + PriceOracle SetPrice cZRX 0.76 + -- + -- Pay back a bunch of debt by liquidating + Prep Jared 10e18 BAT cBAT + Liquidate Jared "->" Geoff 0.9e18 cBAT "Seizing" cZRX + Assert Equal (CToken cBAT BorrowBalance Geoff) 0.1e18 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 0.127368422e18 + -- Do it again, and note that the collateral is gone but borrows remain + -- if we had set the close factor lower, it would just take more steps + Liquidate Jared "->" Geoff 0.0880000008e18 cBAT "Seizing" cZRX + Assert Equal (CToken cBAT BorrowBalance Geoff) 0.0119999992e18 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 0 + +Test "When liquidation incentive is too high to be effective" + -- Happens whenever liquidation discount < collateral factor + -- + -- Start right around the liquidity threshold + NewBorrow borrowAmount:1e18 mintAmount:1.43e18 liquidationIncentive:1.5 + -- + -- Verify that the borrow results in the correct state + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 1.43e18 + -- + -- Put the account underwater s.t. 0.7 < Borrow/Supply + -- i.e. collateral factor < Borrow/Supply + PriceOracle SetPrice cZRX 0.87 + -- + -- Now any amount of debt that we pay back by liquidating will make liquidity worse + -- + -- First, prepare to liquidate + Prep Jared 10e18 BAT cBAT + Expect Changes (Comptroller Liquidity Geoff) -0.024999999076e18 + -- Note that the account collateral ratio will become worse than before + -- although shortfall decreases in absolute terms + -- had Supply/Borrow = 1.430000000 * 0.87 / 1.0 = 1.244100000 + -- now Supply/Borrow = 0.567931036 * 0.87 / 0.5 = 1.135862072 + -- + -- Now perform the liquidation + Liquidate Jared "->" Geoff 0.5e18 cBAT "Seizing" cZRX + -- + -- Verify that the liquidation went through + Assert Equal (CToken cBAT BorrowBalance Geoff) 0.5e18 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 0.567931036e18 + -- + -- Test succeeded which means our expectation was correct + -- liquidity went down after a liquidation! + -- + -- Now lets see that lowering the incentive and liquidating improves the situation + Comptroller LiquidationIncentive 1.2 + Expect Changes (Comptroller Liquidity Geoff) 0.016000000294e18 + Liquidate Jared "->" Geoff 0.1e18 cBAT "Seizing" cZRX diff --git a/spec/scenario/CTokenAdmin.scen b/spec/scenario/CTokenAdmin.scen new file mode 100644 index 000000000..dfd317f82 --- /dev/null +++ b/spec/scenario/CTokenAdmin.scen @@ -0,0 +1,30 @@ + +Test "Set admin" + NewComptroller + NewCToken ZRX cZRX + Assert Equal (CToken cZRX Admin) (Address Root) + Assert Equal (CToken cZRX PendingAdmin) (Address Zero) + From Root (CToken cZRX SetPendingAdmin Geoff) + Assert Equal (CToken cZRX Admin) (Address Root) + Assert Equal (CToken cZRX PendingAdmin) (Address Geoff) + From Geoff (CToken cZRX AcceptAdmin) + Assert Equal (CToken cZRX Admin) (Address Geoff) + Assert Equal (CToken cZRX PendingAdmin) (Address Zero) + +Test "Fail to set pending admin" + NewComptroller + NewCToken ZRX cZRX + Invariant Remains (CToken cZRX Admin) (Address Root) + Invariant Remains (CToken cZRX PendingAdmin) (Address Zero) + AllowFailures + From Geoff (CToken cZRX SetPendingAdmin Geoff) + Assert Failure UNAUTHORIZED SET_PENDING_ADMIN_OWNER_CHECK + +Test "Fail to accept admin" + NewComptroller + NewCToken ZRX cZRX + Invariant Remains (CToken cZRX Admin) (Address Root) + Invariant Remains (CToken cZRX PendingAdmin) (Address Zero) + AllowFailures + From Geoff (CToken cZRX AcceptAdmin) + Assert Failure UNAUTHORIZED ACCEPT_ADMIN_PENDING_ADMIN_CHECK diff --git a/spec/scenario/CoreMacros b/spec/scenario/CoreMacros new file mode 100644 index 000000000..c55ce3956 --- /dev/null +++ b/spec/scenario/CoreMacros @@ -0,0 +1,185 @@ +-- These are included in each scenario + +Macro Successfully + Invariant Success + +Macro AllowFailures + ClearInvariants Success + +Macro PricedComptroller closeFactor=0.1 maxAssets=20 + Unitroller Deploy + PriceOracle Deploy Simple + ComptrollerImpl Deploy Scenario ScenComptroller + Unitroller SetPendingImpl ScenComptroller + PriceOracleProxy Deploy (Unitroller Address) (PriceOracle Address) (Address Zero) (Address Zero) -- Final argument is a Junk address, if listing cEther use ListedEtherToken to replace proxy + ComptrollerImpl ScenComptroller Become (PriceOracleProxy Address) closeFactor maxAssets + +Macro NewComptroller price=1.0 closeFactor=0.1 maxAssets=20 + Unitroller Deploy + PriceOracle Deploy Fixed price + ComptrollerImpl Deploy Scenario ScenComptroller + Unitroller SetPendingImpl ScenComptroller + PriceOracleProxy Deploy (Unitroller Address) (PriceOracle Address) (Address Zero) (Address Zero) -- Junk address, if listing cEther use ListedEtherToken to replace proxy + ComptrollerImpl ScenComptroller Become (PriceOracleProxy Address) closeFactor maxAssets + +Macro NewCToken erc20 cToken borrowRate=0.0005 initialExchangeRate=2e9 decimals=8 tokenType=Standard cTokenType=Scenario + Erc20 Deploy tokenType erc20 erc20 + InterestRateModel Deploy Fixed StdInterest borrowRate -- Note: interest rate model probably shouldn't be global + CToken Deploy cTokenType cToken cToken (Erc20 erc20 Address) (Comptroller Address) (InterestRateModel StdInterest Address) initialExchangeRate decimals + +Macro NewEtherToken cToken borrowRate=0.0005 initialExchangeRate=2e9 decimals=8 + InterestRateModel Deploy Fixed StdInterest borrowRate -- Note: interest rate model probably shouldn't be global + CToken Deploy CEtherScenario cToken cToken (Comptroller Address) (InterestRateModel StdInterest Address) initialExchangeRate decimals + +Macro ListedCToken erc20 cToken borrowRate=0.0005 initialExchangeRate=2e9 decimals=8 tokenType=Standard cTokenType=Scenario + NewCToken erc20 cToken borrowRate initialExchangeRate decimals tokenType cTokenType + Comptroller SupportMarket cToken + +Macro ListedEtherToken cToken borrowRate=0.0005 initialExchangeRate=2e9 decimals=8 + NewEtherToken cToken borrowRate initialExchangeRate decimals + Comptroller SupportMarket cToken + PriceOracleProxy Deploy (Unitroller Address) (PriceOracle Address) (Address cETH) (Address Zero) + Comptroller SetPriceOracle (PriceOracleProxy Address) + +Macro ListedEtherTokenMinted cToken borrowRate=0.0005 initialExchangeRate=2e9 decimals=8 + NewEtherToken cToken borrowRate initialExchangeRate decimals + Comptroller SupportMarket cToken + CallMintEth Root 1e18 cToken + +Macro SetPriceCF cToken price collateralFactor + PriceOracle SetPrice cToken price + Comptroller SetCollateralFactor cToken collateralFactor + +Macro Give user amount erc20 + Erc20 erc20 Faucet user amount + +Macro Donate token amount + (Trx Value amount (CToken token Donate)) + +Macro Prep user amount erc20 token allowanceAmount=Nothing + Erc20 erc20 Faucet user amount + From user (Erc20 erc20 Approve token (Default allowanceAmount amount)) + +Macro Allow user token + From user (Erc20 (CToken token Underlying) Approve token Max) + +Macro AccrueInterest token + CToken token AccrueInterest + +Macro Mint user amount token + From user (CToken token Mint amount) + +Macro SendMintEth user amount token + From user (Trx GasPrice 0 (Trx Value amount (Send token amount))) + +Macro CallMintEth user amount token + From user (Trx GasPrice 0 (Trx Value amount (CToken token Mint))) + +Macro Redeem user amount token + From user (CToken token Redeem amount) + +Macro RedeemEth user amount token + Trx GasPrice 0 (From user (CToken token Redeem amount)) + +Macro RedeemUnderlying user amount token + From user (CToken token RedeemUnderlying amount) + +Macro RedeemUnderlyingEth user amount token + Trx GasPrice 0 (From user (CToken token RedeemUnderlying amount)) + +Macro BorrowEth user amount token + Trx GasPrice 0 (From user (CToken token Borrow amount)) + +Macro Borrow user amount token + From user (CToken token Borrow amount) + +Macro RepayBorrow user amount token + From user (CToken token RepayBorrow amount) + +Macro RepayBorrowEth user amount token + From user (Trx GasPrice 0 (Trx Value amount (CToken token RepayBorrow))) + +Macro RepayBorrowEthMax user amount token + From user (Trx GasPrice 0 (Trx Value amount (Maximillion RepayBehalf user))) + +Macro RepayBorrowBehalf user behalf amount token + From user (CToken token RepayBorrowBehalf behalf amount) + +Macro RepayBorrowEthBehalf user behalf amount token + From user (Trx GasPrice 0 (Trx Value amount (CToken token RepayBorrowBehalf behalf))) + +Macro Liquidate liquidator _ borrower amount token _ collateral + From liquidator (CToken token Liquidate borrower collateral amount) + +Macro LiquidateEthColl liquidator _ borrower amount token _ collateral + From liquidator (Trx GasPrice 0 (CToken token Liquidate borrower collateral amount)) + +Macro LiquidateEthBorrow liquidator _ borrower amount token _ collateral + From liquidator (Trx GasPrice 0 (Trx Value amount (CToken token Liquidate borrower collateral))) + +Macro Seize amount token caller liquidator borrower + From caller (CToken token Seize liquidator borrower amount) + +Macro EvilSeize token amount treasure seizer seizee + CToken token EvilSeize treasure seizer seizee amount + +Macro Support cToken collateralFactor=0.5 + Comptroller SupportMarket cToken + Comptroller SetCollateralFactor cToken collateralFactor + +Macro SetCollateralFactor cToken collateralFactor=0.5 + Comptroller SetCollateralFactor cToken collateralFactor + +Macro ReduceReserves amount token + CToken token ReduceReserves amount + +Macro FastForward n blocks + Comptroller FastForward n blocks + +Macro EnterMarkets user ...markets + From user (Comptroller EnterMarkets markets) + +Macro ExitMarket user market + From user (Comptroller ExitMarket market) + +Macro Transfer from to amount token + From from (Erc20 token Transfer to amount) + +Macro Cash cToken + Read Erc20 (CToken cToken Underlying) TokenBalance cToken + +Macro QuickMint amount cToken from=Me + Give from amount (CToken cToken Underlying) + Allow from cToken + From from (CToken cToken Mint amount) + +Macro QuickBorrow amount cToken ...collateral + From Me (Comptroller EnterMarkets collateral) + From Me (Comptroller EnterMarkets (cToken)) + From Me (CToken cToken Borrow amount) + +-- Macro for performing a borrow with the sole +-- purpose of adding interest to the erc20 market +Macro BorrowAndRepayWithInterest erc20 cToken amount interestAmount interestRate blocks reserveRate=0 + -- TODO: Make invariant success for these? + -- TODO: Named args as macros + InterestRateModel Deploy Fixed Std interestRate + CToken cToken SetInterestRateModel (InterestRateModel Std Address) + CToken cToken SetReserveFactor reserveRate + ListedCToken COLLAT cCOLLAT + Comptroller SetCollateralFactor cCOLLAT 0.9 + Prep Torrey 1e30 COLLAT cCOLLAT + Mint Torrey 1e30 cCOLLAT + EnterMarkets Torrey cCOLLAT cToken + Assert True (Comptroller CheckMembership Torrey cCOLLAT) + Assert True (Comptroller CheckMembership Torrey cToken) + Borrow Torrey amount cToken + -- Cool, we've borrowed, now let's accrue interest then repay all + FastForward blocks Blocks + -- RepayBorrow Torrey (CToken BorrowBalance Torrey) cToken + From Torrey (Erc20 erc20 Approve cToken amount) + RepayBorrow Torrey amount cToken + From Torrey (Erc20 erc20 Approve cToken interestAmount) + Give Torrey interestAmount erc20 + RepayBorrow Torrey interestAmount cToken + Assert Equal (CToken cToken BorrowBalance Torrey) Zero diff --git a/spec/scenario/EnterExitMarkets.scen b/spec/scenario/EnterExitMarkets.scen new file mode 100644 index 000000000..aefc43955 --- /dev/null +++ b/spec/scenario/EnterExitMarkets.scen @@ -0,0 +1,157 @@ +-- Enter and Exit Markets Tests + +Test "Enter Markets Idempotent" + NewComptroller + Assert Equal (Comptroller MembershipLength Geoff) Zero + Assert Equal (Comptroller AssetsIn Geoff) [] + ListedCToken ZRX cZRX + EnterMarkets Geoff cZRX + Assert Log MarketEntered (cToken (Address cZRX)) (account (Address Geoff)) + Assert Equal (Comptroller MembershipLength Geoff) (Exactly 1) + Assert True (Comptroller CheckMembership Geoff cZRX) + ListedCToken OMG cOMG + EnterMarkets Geoff cZRX cOMG + Assert Equal (Comptroller MembershipLength Geoff) (Exactly 2) + Assert True (Comptroller CheckMembership Geoff cZRX) + Assert True (Comptroller CheckMembership Geoff cOMG) + Assert Equal (Comptroller AssetsIn Geoff) [(Address cZRX) (Address cOMG)] + +Test "Entered Market Must Be Supported" + NewComptroller + Assert Equal (Comptroller MembershipLength Geoff) Zero + ListedCToken ZRX cZRX + EnterMarkets Geoff cZRX + Assert Equal (Comptroller MembershipLength Geoff) (Exactly 1) + NewCToken OMG cOMG + EnterMarkets Geoff cZRX cOMG + Assert Equal (Comptroller MembershipLength Geoff) (Exactly 1) + Assert True (Comptroller CheckMembership Geoff cZRX) + Assert False (Comptroller CheckMembership Geoff cOMG) + Support cOMG + EnterMarkets Geoff cZRX cOMG + Assert Equal (Comptroller MembershipLength Geoff) (Exactly 2) + Assert True (Comptroller CheckMembership Geoff cZRX) + Assert True (Comptroller CheckMembership Geoff cOMG) + +Test "Cannot enter Markets beyond max assets" + NewComptroller + Comptroller SetMaxAssets 1 + Assert Equal (Comptroller MembershipLength Geoff) Zero + ListedCToken ZRX cZRX + ListedCToken OMG cOMG + EnterMarkets Geoff cZRX cOMG + Assert Equal (Comptroller MembershipLength Geoff) (Exactly 1) + Assert True (Comptroller CheckMembership Geoff cZRX) + Assert False (Comptroller CheckMembership Geoff cOMG) + +Test "Exit single market" + NewComptroller + ListedCToken ZRX cZRX + EnterMarkets Geoff cZRX + Assert Equal (Comptroller AssetsIn Geoff) [(Address cZRX)] + ExitMarket Geoff cZRX + Assert Equal (Comptroller AssetsIn Geoff) [] + +Test "Exit non-entered market" + NewComptroller + ListedCToken ZRX cZRX + ExitMarket Geoff cZRX + Assert Equal (Comptroller AssetsIn Geoff) [] + +Test "Exit one of two market from the front" + NewComptroller + ListedCToken ZRX cZRX + ListedCToken OMG cOMG + EnterMarkets Geoff cZRX cOMG + Assert Equal (Comptroller AssetsIn Geoff) [(Address cZRX) (Address cOMG)] + ExitMarket Geoff cZRX + Assert Equal (Comptroller AssetsIn Geoff) [(Address cOMG)] + +Test "Exit one of two market from the back" + NewComptroller + ListedCToken ZRX cZRX + ListedCToken OMG cOMG + EnterMarkets Geoff cZRX cOMG + Assert Equal (Comptroller AssetsIn Geoff) [(Address cZRX) (Address cOMG)] + ExitMarket Geoff cOMG + Assert Equal (Comptroller AssetsIn Geoff) [(Address cZRX)] + +Test "Exit multiple markets" + NewComptroller + ListedCToken ZRX cZRX + ListedCToken OMG cOMG + ListedCToken BAT cBAT + ListedCToken REP cREP + ListedCToken DAI cDAI + EnterMarkets Geoff cZRX cOMG cBAT cREP cDAI + Assert Equal (Comptroller AssetsIn Geoff) [(Address cZRX) (Address cOMG) (Address cBAT) (Address cREP) (Address cDAI)] + ExitMarket Geoff cZRX + Assert Equal (Comptroller AssetsIn Geoff) [(Address cDAI) (Address cOMG) (Address cBAT) (Address cREP)] + ExitMarket Geoff cREP + Assert Equal (Comptroller AssetsIn Geoff) [(Address cDAI) (Address cOMG) (Address cBAT)] + ExitMarket Geoff cOMG + Assert Equal (Comptroller AssetsIn Geoff) [(Address cDAI) (Address cBAT)] + ExitMarket Geoff cDAI + Assert Equal (Comptroller AssetsIn Geoff) [(Address cBAT)] + ExitMarket Geoff cBAT + Assert Equal (Comptroller AssetsIn Geoff) [] + +Test "Realistic Market Scenario" + PricedComptroller + ListedCToken ZRX cZRX + SetPriceCF cZRX 0.002 0.4 + ListedEtherToken cETH + Comptroller SetCollateralFactor cEth 0.8 + ListedCToken BAT cBAT + SetPriceCF cBAT 0.0015 0.3 + -- Mint some cZRX and cETH + Prep Geoff 1250e18 ZRX cZRX + Mint Geoff 1250e18 cZRX -- Liquidity -> 0.4 * 0.002 * 1250e18 = 1.0e18 + SendMintEth Geoff 2.5e18 cETH -- Liqiuidity -> 0.8 * 1.0 * 2.5e18 = 2.0e18 + -- Check liquidity is zero when not in any markets + Assert Equal (Comptroller Liquidity Geoff) Zero + -- Enter ZRX and check liquidity + EnterMarkets Geoff cZRX + Assert Equal (Comptroller Liquidity Geoff) 1.0e18 + -- Try to borrow BAT but fail + HoldInvariants + Borrow Geoff 1.0e27 cBAT + Assert Failure COMPTROLLER_REJECTION BORROW_COMPTROLLER_REJECTION MARKET_NOT_ENTERED + -- Enter BAT for borrowing + EnterMarkets Geoff cBAT + -- Fail to borrow BAT due to liquidity + Give cBAT 1000e18 BAT + HoldInvariants + Borrow Geoff 1000e18 cBAT -- 1000e18 * 0.0015 = 1.5e18 required liquidity + -- But since we're only in ZRX, we only have 1.0e18 liquidity + Assert Failure COMPTROLLER_REJECTION BORROW_COMPTROLLER_REJECTION INSUFFICIENT_LIQUIDITY + -- Enter cETH and check liquidity + EnterMarkets Geoff cETH + Assert Equal (Comptroller Liquidity Geoff) 3.0e18 -- Sum of cETH and cZRX liquidity from above + -- Borrow previous BAT amount given liquidity + Borrow Geoff 1000e18 cBAT + Assert Equal (Comptroller Liquidity Geoff) 1.5e18 -- Less the borrow amount's toll + -- Try to exit a eth market but fail due to given borrow requiring eth as collateral + HoldInvariants + ExitMarket Geoff cETH + Assert Failure REJECTION EXIT_MARKET_REJECTION INSUFFICIENT_LIQUIDITY -- Liquidity check fails + Assert Equal (Comptroller AssetsIn Geoff) [(Address cZRX) (Address cBAT) (Address cETH)] + -- Repay some borrow and exit market OMG + Allow Geoff cBAT + RepayBorrow Geoff 500e18 cBAT + Assert Equal (Comptroller Liquidity Geoff) 2.25e18 -- With 0.75e18 repaid + ExitMarket Geoff cETH + Assert Equal (Comptroller AssetsIn Geoff) [(Address cZRX) (Address cBAT)] + Assert Equal (Comptroller Liquidity Geoff) 0.25e18 -- Less Eth's 2.0e18 collateral weight + -- Try and exit cBAT (firist without, then after, repaying) + HoldInvariants + ExitMarket Geoff cBAT + Assert Failure NONZERO_BORROW_BALANCE EXIT_MARKET_BALANCE_OWED + RepayBorrow Geoff Max cBAT + ExitMarket Geoff cBAT + Assert Equal (Comptroller AssetsIn Geoff) [(Address cZRX)] + Assert Equal (Comptroller Liquidity Geoff) 1.0e18 -- Back to just cZRX + -- Exit cZRX + ExitMarket Geoff cZRX + Assert Equal (Comptroller AssetsIn Geoff) [] + Assert Equal (Comptroller Liquidity Geoff) 0e18 -- Back to nothing diff --git a/spec/scenario/Excel.scen.old b/spec/scenario/Excel.scen.old new file mode 100644 index 000000000..f2cb486cc --- /dev/null +++ b/spec/scenario/Excel.scen.old @@ -0,0 +1,119 @@ +-- Auto-generated tests from Excel + +Test "Excel Scenario 1 https://docs.google.com/spreadsheets/d/14kRju5M3t0wL-OPSNPV-j1raXgArb0IdsL7hMqKQuyI/edit#gid=1178589286" + -- Excel Base Setup + SetOriginationFee "0" + SetCollateralRatio "1.1" + AddToken Ether + SupportMarket Ether (FixedPrice 1.0) WhitepaperRate SimplePolicyHook + AddToken OMG + SupportMarket OMG (FixedPrice 0.05) WhitepaperRate SimplePolicyHook + Approve Bank Ether "1e30" + Approve Bank OMG "1e30" + Approve Geoff Ether "1e30" + Approve Geoff OMG "1e30" + Approve Torrey Ether "1e30" + Approve Torrey OMG "1e30" + Approve Robert Ether "1e30" + Approve Robert OMG "1e30" + Faucet Bank Ether "1e30" + Faucet Bank OMG "1e30" + Faucet Geoff Ether "1e30" + Faucet Geoff OMG "1e30" + Faucet Torrey Ether "1e30" + Faucet Torrey OMG "1e30" + Faucet Robert Ether "1e30" + Faucet Robert OMG "1e30" + -- + -- Scenario 1 + Supply Bank Ether "1000.00000000e18" + Assert Success + Assert Equal (SupplyBalance Bank Ether) (Precisely "1000.00000000e18") + Supply Bank OMG "3000.00000000e18" + Assert Success + Assert Equal (SupplyBalance Bank OMG) (Precisely "3000.00000000e18") + FastForward 20 Blocks + Supply Geoff Ether "200.00000000e18" + Assert Success + Assert Equal (SupplyBalance Geoff Ether) (Precisely "200.00000000e18") + FastForward 10 Blocks + EnterMarkets Geoff OMG + Borrow Geoff OMG "2500.00000000e18" + Assert Success + Assert Equal (BorrowBalance Geoff OMG) (Precisely "2500.00000000e18") + FastForward 10 Blocks + Supply Torrey OMG "2500.00000000e18" + Assert Success + Assert Equal (SupplyBalance Torrey OMG) (Precisely "2500.00000000e18") + FastForward 10 Blocks + EnterMarkets Torrey Ether + Borrow Torrey Ether "97.00000000e18" + Assert Success + Assert Equal (BorrowBalance Torrey Ether) (Precisely "97.00000000e18") + FastForward 10 Blocks + Withdraw Bank Ether "780.00000000e18" + Assert Success + Assert Equal (SupplyBalance Bank Ether) (Precisely "220.00002988e18") + FastForward 10 Blocks + Withdraw Bank OMG "2000.00000000e18" + Assert Success + Assert Equal (SupplyBalance Bank OMG) (Precisely "1000.00900609e18") + FastForward 10 Blocks + Supply Robert OMG "5000.00000000e18" + Assert Success + Assert Equal (SupplyBalance Robert OMG) (Precisely "5000.00000000e18") + FastForward 10 Blocks + EnterMarkets Robert Ether + Borrow Robert Ether "115.00000000e18" + Assert Success + Assert Equal (BorrowBalance Robert Ether) (Precisely "115.00000000e18") + FastForward 10 Blocks + PayBorrow Geoff OMG "2000.00000000e18" + Assert Success + Assert Equal (BorrowBalance Geoff OMG) (Precisely "500.02288785e18") + FastForward 10 Blocks + Withdraw Geoff Ether "30.00000000e18" + Assert Success + Assert Equal (SupplyBalance Geoff Ether) (Precisely "170.00033682e18") + FastForward 40 Blocks + Withdraw Robert OMG "1000.00000000e18" + Assert Success + Assert Equal (SupplyBalance Robert OMG) (Precisely "4000.00277737e18") + +Test "Excel Scenario 2 https://docs.google.com/spreadsheets/d/14kRju5M3t0wL-OPSNPV-j1raXgArb0IdsL7hMqKQuyI/edit#gid=585013245" + -- Excel Base Setup + SetOriginationFee "0" + SetCollateralRatio "1.1" + AddToken Ether + SupportMarket Ether (FixedPrice 1.0) WhitepaperRate SimplePolicyHook + AddToken OMG + SupportMarket OMG (FixedPrice 0.05) WhitepaperRate SimplePolicyHook + Approve Bank Ether "1e30" + Approve Bank OMG "1e30" + Approve Geoff Ether "1e30" + Approve Geoff OMG "1e30" + Approve Torrey Ether "1e30" + Approve Torrey OMG "1e30" + Approve Robert Ether "1e30" + Approve Robert OMG "1e30" + Faucet Bank Ether "1e30" + Faucet Bank OMG "1e30" + Faucet Geoff Ether "1e30" + Faucet Geoff OMG "1e30" + Faucet Torrey Ether "1e30" + Faucet Torrey OMG "1e30" + Faucet Robert Ether "1e30" + Faucet Robert OMG "1e30" + -- + -- Scenario 2 + Supply Geoff Ether "1000.00000000e18" + Assert Success + Assert Equal (SupplyBalance Geoff Ether) (Precisely "1000.00000000e18") + EnterMarkets Geoff Ether + Borrow Geoff Ether "310.00000000e18" + Assert Success + Assert Equal (BorrowBalance Geoff Ether) (Precisely "310.00000000e18") + FastForward 40 Blocks + Supply Geoff Ether "0.00000000e18" + Assert Success + Assert Equal (SupplyBalance Geoff Ether) (Precisely "1000.00100590e18") diff --git a/spec/scenario/ExchangeRate.scen b/spec/scenario/ExchangeRate.scen new file mode 100644 index 000000000..2db30838b --- /dev/null +++ b/spec/scenario/ExchangeRate.scen @@ -0,0 +1,73 @@ + +Test "Initial Exchange Rate" + NewComptroller + NewCToken ZRX cZRX initialExchangeRate:2e9 + Assert Equal (CToken cZRX ExchangeRateStored) (Exp 2e9) + +Test "Initial Exchange Rate with Mint" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:5e9 + -- Check initial exchange holds + Invariant Remains (CToken cZRX ExchangeRateStored) (Exp 5e9) + -- Mint some tokens and verify invariant still holds + Prep Geoff Some ZRX cZRX + Mint Geoff 50e18 cZRX + -- Also, verify token was minted at given exchange rate + Assert Equal (Erc20 cZRX TotalSupply) (Exactly 10e9) + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 10e9) + -- Let's mint again and verify it's still good. + Prep Torrey Some ZRX cZRX + Mint Torrey 50e18 cZRX + -- Also, verify token was minted at given exchange rate + Assert Equal (Erc20 cZRX TotalSupply) (Exactly 20e9) + Assert Equal (Erc20 cZRX TokenBalance Torrey) (Exactly 10e9) + +Test "ZRX: Exch. Rate:2e9, Cash(51e18) + Borrows(2.0e18) - Reserves(0.5e18) / Tokens(2.5e10)" + NewComptroller + -- Decimals You=18, Decimals Us=8 -> 2e9 Exchange Rate + ListedCToken ZRX cZRX initialExchangeRate:2e9 decimals:8 + Assert Equal (CToken cZRX ExchangeRateStored) (Exp 2e9) + -- Mint 50.0 ZRX at given exchange rate + Prep Geoff Some ZRX cZRX + Assert Equal (Erc20 cZRX TotalSupply) Zero + Mint Geoff 50e18 cZRX + -- 50e18 / 2e9 = 2.5e10 + Assert Equal (Erc20 cZRX TotalSupply) (Exactly 2.5e10) + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 2.5e10) + -- Set cash + Erc20 ZRX Faucet cZRX 1.0e18 + Assert Equal (Erc20 ZRX TokenBalance cZRX) (Exactly 51.0e18) + -- Mock total borrows + CToken cZRX Mock totalBorrows 2.0e18 + Assert Equal (CToken cZRX TotalBorrows) (Exactly 2.0e18) + -- Mock total reserves + CToken cZRX Mock totalReserves 0.5e18 + Assert Equal (CToken cZRX Reserves) (Exactly 0.5e18) + -- Okay, we're all set, let's check the exchange rate + -- (51+2-0.5)e18/2.5e10 = 52.5e18/2.5e10 = 21e8 -> 21e26 (Exp) + Assert Equal (CToken cZRX ExchangeRateStored) (Exp 2.1e9) + +Test "USDC: Exch. Rate:2e-3, Cash(51e18) + Borrows(2.0e18) - Reserves(0.5e18) / Tokens(2.5e10)" + NewComptroller + -- Decimals You=6, Decimals Us=8 -> 2e-3 Exchange Rate + ListedCToken USDC cUSDC initialExchangeRate:2e-3 decimals:8 + Assert Equal (CToken cUSDC ExchangeRateStored) (Exp 2e-3) + -- Mint 50.0 USDC at given exchange rate + Prep Geoff Little USDC cUSDC + Assert Equal (Erc20 cUSDC TotalSupply) (Exactly 0.0) + Mint Geoff 50e6 cUSDC + -- 5.0e7 / 2e-3 = 2.5e10 + Assert Equal (Erc20 cUSDC TotalSupply) (Exactly 2.5e10) + Assert Equal (Erc20 cUSDC TokenBalance Geoff) (Exactly 2.5e10) + -- Set cash + Erc20 USDC Faucet cUSDC 2.0e6 + Assert Equal (Erc20 USDC TokenBalance cUSDC) (Exactly 52.0e6) + -- Mock total borrows + CToken cUSDC Mock totalBorrows 5.0e6 + Assert Equal (CToken cUSDC TotalBorrows) (Exactly 5.0e6) + -- Mock total reserves + CToken cUSDC Mock totalReserves 1.5e6 + Assert Equal (CToken cUSDC Reserves) (Exactly 1.5e6) + -- Okay, we're all set, let's check the exchange rate + -- (52+5-1.5)e6/2.5e10 = 55.5e6/2.5e10 = 2.22e-3 -> 2.22e15 (Exp) + Assert Equal (CToken cUSDC ExchangeRateStored) (Exp 2.22e-3) diff --git a/spec/scenario/HypotheticalAccountLiquidity.scen b/spec/scenario/HypotheticalAccountLiquidity.scen new file mode 100644 index 000000000..0028795fc --- /dev/null +++ b/spec/scenario/HypotheticalAccountLiquidity.scen @@ -0,0 +1,49 @@ + +Test "Calculates hypothetical account liquidity" + -- Note, this comes a bit from `EnterExitMarkets` Scenario + PricedComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + SetPriceCF cZRX 0.002 0.4 + ListedEtherToken cETH initialExchangeRate:1e9 + Comptroller SetCollateralFactor cEth 0.8 + ListedCToken BAT cBAT initialExchangeRate:1e9 + SetPriceCF cBAT 0.0015 0.3 + ListedCToken OMG cOMG initialExchangeRate:1e9 + NewCToken REP cREP + -- Mint some cZRX and cETH + Prep Geoff 1250e18 ZRX cZRX + Mint Geoff 1250e18 cZRX -- Liquidity -> 0.4 * 0.002 * 1250e18 = 1.0e18 + SendMintEth Geoff 2.5e18 cETH -- Liqiuidity -> 0.8 * 1.0 * 2.5e18 = 2.0e18 + -- Check liquidity is zero when not in any markets + Assert Equal (Comptroller Liquidity Geoff) Zero + -- Enter ZRX and check liquidity + EnterMarkets Geoff cZRX + Assert Equal (Comptroller Liquidity Geoff) 1.0e18 + -- Now let's look at some hypotheticals + Assert Equal (Comptroller Hypothetical Geoff Redeems 1000e9 cZRX) 0.2e18 -- 0.4 * 0.002 * -1000e18 = -0.8e18 + Assert Equal (Comptroller Hypothetical Geoff Borrows 1000e18 cZRX) -1e18 -- 0.002 * -1000e18 = -2e18 + -- Note, if you're not in an asset, this function returns no effect + Assert Equal (Comptroller Hypothetical Geoff Redeems 0.002e9 cETH) 1.0e18 -- 0.8 * 1000.0 * -0.002e18 = -1.6e18 + Assert Equal (Comptroller Hypothetical Geoff Borrows 0.002e18 cETH) 1.0e18 -- 1000.0 * -0.002e18 = -2e18 + EnterMarkets Geoff cETH + Assert Equal (Comptroller Liquidity Geoff) 3.0e18 + Assert Equal (Comptroller Hypothetical Geoff Redeems 1000e9 cZRX) 2.2e18 -- 0.4 * 0.002 * -1000e18 = -0.8e18 + Assert Equal (Comptroller Hypothetical Geoff Borrows 1000e18 cZRX) 1e18 -- 0.002 * -1000e18 = -2e18 + Assert Equal (Comptroller Hypothetical Geoff Redeems 2e9 cETH) 1.4e18 -- 0.8 * 1.0 * -2e18 = -1.6e18 + Assert Equal (Comptroller Hypothetical Geoff Borrows 2e18 cETH) 1.0e18 -- 1.0 * -2e18 = -2e18 + EnterMarkets Geoff cBAT + Assert Equal (Comptroller Hypothetical Geoff Redeems 1000e9 cBAT) 2.55e18 -- 0.3 * 0.0015 * -1000e18 = -0.45e18e18 + Assert Equal (Comptroller Hypothetical Geoff Borrows 1000e18 cBAT) 1.5e18 -- 0.0015 * -1000e18 = -1.5e18 + EnterMarkets Geoff cOMG + -- Fails if the given asset doesn't have a price + Assert ReadError (Comptroller Hypothetical Geoff Redeems 1e20 cOMG) "Failed to compute account hypothetical liquidity: error code = 13" + Assert ReadError (Comptroller Hypothetical Geoff Borrows 1e20 cOMG) "Failed to compute account hypothetical liquidity: error code = 13" + PriceOracle SetPrice cOMG 0.01 + -- Has a price and now is listed + Assert Equal (Comptroller Hypothetical Geoff Redeems 100e9 cOMG) 3.0e18 -- No collateral factor + Assert Equal (Comptroller Hypothetical Geoff Borrows 100e18 cOMG) 2.0e18 -- 0.01 * -100e18 = -1e18 + -- For a token has no price and isn't listed + -- Note: we can't actually enter the unlisted market without some harness function + -- we could consider testing this, but it would be out of the scope of scenarios + Assert Equal (Comptroller Hypothetical Geoff Redeems 100e18 cREP) 3.0e18 -- No effect + Assert Equal (Comptroller Hypothetical Geoff Borrows 100e18 cREP) 3.0e18 -- No effect diff --git a/spec/scenario/Liquidate.scen b/spec/scenario/Liquidate.scen new file mode 100644 index 000000000..e47f60f7d --- /dev/null +++ b/spec/scenario/Liquidate.scen @@ -0,0 +1,520 @@ + +Macro NewBorrow borrowAmount borrowRate user=Geoff collateralPrice=1.0 borrowPrice=1.0 mintAmount=100e18 collateralTokenType=Standard borrowTokenType=Standard + PricedComptroller + Comptroller LiquidationIncentive 1.1 + NewCToken ZRX cZRX 0.0005 2e9 8 collateralTokenType + NewCToken BAT cBAT borrowRate 2e9 8 borrowTokenType -- note: cannot use macros with named args right now + Give cBAT 10e18 BAT -- Faucet some bat to borrow + PriceOracle SetPrice cZRX collateralPrice + Support cZRX collateralFactor:0.5 + PriceOracle SetPrice cBAT borrowPrice + Support cBAT collateralFactor:0 + SimpleBorrow user borrowAmount mintAmount + +Macro SimpleBorrow user borrowAmount mintAmount + Prep user mintAmount ZRX cZRX + Mint user mintAmount cZRX + EnterMarkets user cZRX cBAT + Borrow user borrowAmount cBAT + +Test "Insufficient shortfall" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 98000 Blocks -- 1e18 * (1 + 98000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 50e18 + Assert Equal (CToken cBAT TotalBorrows) 50e18 + -- Check user liquidity and verify equals 0 + Assert Equal (Comptroller Liquidity Geoff) 0e18 + -- At exactly zero, should not be able to liquidate + Prep Torrey 10e18 BAT cBAT + AllowFailures + Liquidate Torrey "->" Geoff 10e18 cBAT "Seizing" cZRX + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_COMPTROLLER_REJECTION INSUFFICIENT_SHORTFALL + +Test "Cannot self-liquidate" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Assert Equal (CToken cBAT TotalBorrows) 51e18 + -- Check user liquidity and verify < 0 + Assert Equal (Comptroller Liquidity Geoff) -1e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Geoff 10e18 BAT cBAT + AllowFailures + Liquidate Geoff "->" Geoff 2e18 cBAT "Seizing" cZRX + Assert Failure INVALID_ACCOUNT_PAIR LIQUIDATE_LIQUIDATOR_IS_BORROWER + +Test "Liqidate beyond max close" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Assert Equal (CToken cBAT TotalBorrows) 51e18 + -- Check user liquidity and verify < 0 + Assert Equal (Comptroller Liquidity Geoff) -1e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 10e18 BAT cBAT + AllowFailures + Liquidate Torrey "->" Geoff 10e18 cBAT "Seizing" cZRX + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_COMPTROLLER_REJECTION TOO_MUCH_REPAY + +Test "Proper liquidation with 1:1 price ratio" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices are 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a lot of blocks at a 0.05% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Assert Equal (CToken cBAT TotalBorrows) 51e18 + -- Check user liquidity and verify < 0 + Assert Equal (Comptroller Liquidity Geoff) -1e18 -- recheck + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 2e18 BAT cBAT + -- + -- Let's check how values start before liqudation + -- Note: we're going to be some-what exhausive in what we check + Invariant Remains (Erc20 ZRX TokenBalance Geoff) 0e18 -- all was minted + Invariant Remains (Erc20 ZRX TokenBalance Torrey) 0e18 -- didn't have any beforehand + Invariant Remains (Erc20 ZRX TokenBalance cZRX) 100e18 -- from minting + Assert Equal (Erc20 cZRX TokenBalance Geoff) 50e9 -- from minting + Assert Equal (Erc20 cZRX TokenBalance Torrey) 0e9 -- never had any + Invariant Remains (Erc20 BAT TokenBalance Geoff) 1e18 -- original amount borrowed + Assert Equal (Erc20 BAT TokenBalance Torrey) 2e18 -- from prep above + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 -- had 10e18, lent 1e18 to geoff + Invariant Remains (Erc20 cBAT TokenBalance Geoff) 0e9 -- never had any (has underlying) + Invariant Remains (Erc20 cBAT TokenBalance Torrey) 0e9 -- never had any + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 51e18 -- all that interest + Assert Equal (CToken cBAT TotalBorrows) 51e18 -- all those borrowers + -- Do the liquidation + Liquidate Torrey "->" Geoff 2e18 cBAT "Seizing" cZRX + -- + -- And see what they are now + Assert Equal (Erc20 cZRX TokenBalance Geoff) 48.9e9 -- 1:1 -> 2e18 x 1.1 ÷ 2e19 [exchange rate] = 1.1e9 -> Torrey + Assert Equal (Erc20 cZRX TokenBalance Torrey) 1.1e9 -- never had any + Assert Equal (Erc20 BAT TokenBalance Torrey) 0e18 -- repaid + Assert Equal (Erc20 BAT TokenBalance cBAT) 11e18 -- had 10e18, lent 1e18 to geoff, repaid 2 + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 49e18 -- less closed amount + Assert Equal (CToken cBAT TotalBorrows) 49e18 -- + -- Prices are 1:1 and collateral factor is 0.5 + -- User now has 48.9 outstanding supply (yielding 48.9e18 borrowing capacity) + -- The user also has a 49e18 borrow outstanding. + -- Thus the liquidity is (48.9-49)e18 or -0.1e18. + Assert Equal (Comptroller Liquidity Geoff) -0.1e18 + +Test "Proper liquidation with 2:1 price ratio" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 borrowPrice:2.0 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices are 2:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a lot blocks at a 0.05% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Assert Equal (CToken cBAT TotalBorrows) 51e18 + -- Check user liquidity and verify < 0 + Assert Equal (Comptroller Liquidity Geoff) -52e18 -- ( ( 1.0 * 100e18 * 0.5 ) - ( 2.0 * 51e18 ) ) / 1e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 2e18 BAT cBAT + -- + -- Let's check how values start before liqudation + -- Note: we're going to be some-what exhausive in what we check + Invariant Remains (Erc20 ZRX TokenBalance Geoff) 0e18 -- all was minted + Invariant Remains (Erc20 ZRX TokenBalance Torrey) 0e18 -- never had any + Invariant Remains (Erc20 ZRX TokenBalance cZRX) 100e18 -- from minting + Assert Equal (Erc20 cZRX TokenBalance Geoff) 50e9 -- from minting + Assert Equal (Erc20 cZRX TokenBalance Torrey) 0e9 -- never had any + Invariant Remains (Erc20 BAT TokenBalance Geoff) 1e18 -- original amount borrowed + Assert Equal (Erc20 BAT TokenBalance Torrey) 2e18 -- from prep above + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 -- had 10e18, lent 1e18 to geoff + Invariant Remains (Erc20 cBAT TokenBalance Geoff) 0e9 -- never had any (has underlying) + Invariant Remains (Erc20 cBAT TokenBalance Torrey) 0e9 -- never had any + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 51e18 -- all that interest + Assert Equal (CToken cBAT TotalBorrows) 51e18 -- all those borrowers + -- Do the liquidation + Liquidate Torrey "->" Geoff 2e18 cBAT "Seizing" cZRX -- should now take twice as much collateral + -- + -- And see what they are now + Assert Equal (Erc20 cZRX TokenBalance Geoff) 47.8e9 -- 2:1 -> 2 x 2e18 x 1.1 ÷ 2e19 [exchange rate] = 2.2e9 -> Torrey + Assert Equal (Erc20 cZRX TokenBalance Torrey) 2.2e9 -- didn't have any beforehand + Assert Equal (Erc20 BAT TokenBalance Torrey) 0e18 -- repaid + Assert Equal (Erc20 BAT TokenBalance cBAT) 11e18 -- had 10e18, lent 1e18 to geoff, repaid 2 + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 49e18 -- less closed amount + Assert Equal (CToken cBAT TotalBorrows) 49e18 -- + -- Prices are 2:1 and collateral factor is 0.5 + -- User now has 47.8 outstanding supply (yielding 48.9e18 borrowing capacity due + -- to the offsetting collateral factor and exchange rates). + -- The user also has a 49e18 borrow outstanding which is weighted 2:1. + -- Thus the liquidity is (47.8-(2*49))e18 or -50.2e18. + Assert Equal (Comptroller Liquidity Geoff) -50.2e18 + +Test "Liquidate exactly zero" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Invariant Remains (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Invariant Remains (CToken cBAT TotalBorrows) 51e18 + -- Check user liquidity and verify < 0 + Invariant Remains (Comptroller Liquidity Geoff) -1e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 10e18 BAT cBAT + AllowFailures + Liquidate Torrey "->" Geoff 0e18 cBAT "Seizing" cZRX + Assert Failure INVALID_CLOSE_AMOUNT_REQUESTED LIQUIDATE_CLOSE_AMOUNT_IS_ZERO + +Test "When price oracle for collateral token is zero" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Invariant Remains (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Invariant Remains (CToken cBAT TotalBorrows) 51e18 + -- Check user liquidity and verify < 0 + Assert Equal (Comptroller Liquidity Geoff) -1e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 10e18 BAT cBAT + PriceOracle SetPrice cZRX 0 + AllowFailures + Liquidate Torrey "->" Geoff 2e18 cBAT "Seizing" cZRX + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_COMPTROLLER_REJECTION PRICE_ERROR + +Test "When price oracle for collateral token is whack" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Invariant Remains (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Invariant Remains (CToken cBAT TotalBorrows) 51e18 + -- Check user liquidity and verify < 0 + Assert Equal (Comptroller Liquidity Geoff) -1e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 10e18 BAT cBAT + PriceOracle SetPrice cZRX Max + AllowFailures + Liquidate Torrey "->" Geoff 2e18 cBAT "Seizing" cZRX + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_COMPTROLLER_REJECTION MATH_ERROR + +Test "When price oracle for borrow token is zero" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Invariant Remains (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Invariant Remains (CToken cBAT TotalBorrows) 51e18 + -- Check user liquidity and verify < 0 + Assert Equal (Comptroller Liquidity Geoff) -1e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 10e18 BAT cBAT + PriceOracle SetPrice cBAT 0 + AllowFailures + Liquidate Torrey "->" Geoff 2e18 cBAT "Seizing" cZRX + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_COMPTROLLER_REJECTION PRICE_ERROR + +Test "When price oracle for borrow token is whack" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Invariant Remains (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Invariant Remains (CToken cBAT TotalBorrows) 51e18 + -- Check user liquidity and verify < 0 + Assert Equal (Comptroller Liquidity Geoff) -1e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 10e18 BAT cBAT + PriceOracle SetPrice cBAT Max + AllowFailures + Liquidate Torrey "->" Geoff 2e18 cBAT "Seizing" cZRX + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_COMPTROLLER_REJECTION MATH_ERROR + +Test "When repay borrow fails" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Invariant Remains (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Invariant Remains (CToken cBAT TotalBorrows) 51e18 + -- Check user liquidity and verify < 0 + Invariant Remains (Comptroller Liquidity Geoff) -1e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 10e18 BAT cBAT allowanceAmount:0.1e18 + AllowFailures + Liquidate Torrey "->" Geoff 2e18 cBAT "Seizing" cZRX + Assert Failure TOKEN_INSUFFICIENT_ALLOWANCE REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE + + +Test "Proper liquidation of paused WBTC as collateral" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 collateralTokenType:WBTC + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices are 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a lot of blocks at a 0.05% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Assert Equal (CToken cBAT TotalBorrows) 51e18 + -- Check user liquidity and verify < 0 + Assert Equal (Comptroller Liquidity Geoff) -1e18 -- recheck + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 2e18 BAT cBAT + -- + -- Let's check how values start before liqudation + -- Note: we're going to be some-what exhausive in what we check + Invariant Remains (Erc20 ZRX TokenBalance Geoff) 0e18 -- all was minted + Invariant Remains (Erc20 ZRX TokenBalance Torrey) 0e18 -- didn't have any beforehand + Invariant Remains (Erc20 ZRX TokenBalance cZRX) 100e18 -- from minting + Assert Equal (Erc20 cZRX TokenBalance Geoff) 50e9 -- from minting + Assert Equal (Erc20 cZRX TokenBalance Torrey) 0e9 -- never had any + Invariant Remains (Erc20 BAT TokenBalance Geoff) 1e18 -- original amount borrowed + Assert Equal (Erc20 BAT TokenBalance Torrey) 2e18 -- from prep above + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 -- had 10e18, lent 1e18 to geoff + Invariant Remains (Erc20 cBAT TokenBalance Geoff) 0e9 -- never had any (has underlying) + Invariant Remains (Erc20 cBAT TokenBalance Torrey) 0e9 -- never had any + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 51e18 -- all that interest + Assert Equal (CToken cBAT TotalBorrows) 51e18 -- all those borrowers + -- Pause "WBTC" + Erc20 ZRX Pause -- Actually a WBTC token + -- Do the liquidation + Liquidate Torrey "->" Geoff 2e18 cBAT "Seizing" cZRX + -- + -- And see what they are now + Assert Equal (Erc20 cZRX TokenBalance Geoff) 48.9e9 -- 1:1 -> 2e18 x 1.1 ÷ 2e19 [exchange rate] = 1.1e9 -> Torrey + Assert Equal (Erc20 cZRX TokenBalance Torrey) 1.1e9 -- never had any + Assert Equal (Erc20 BAT TokenBalance Torrey) 0e18 -- repaid + Assert Equal (Erc20 BAT TokenBalance cBAT) 11e18 -- had 10e18, lent 1e18 to geoff, repaid 2 + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 49e18 -- less closed amount + Assert Equal (CToken cBAT TotalBorrows) 49e18 -- + -- Prices are 1:1 and collateral factor is 0.5 + -- User now has 48.9 outstanding supply (yielding 48.9e18 borrowing capacity) + -- The user also has a 49e18 borrow outstanding. + -- Thus the liquidity is (48.9-49)e18 or -0.1e18. + Assert Equal (Comptroller Liquidity Geoff) -0.1e18 + + +Test "When WBTC token as borrowed is paused, cannot liquidate" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 borrowTokenType:WBTC + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Invariant Remains (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Invariant Remains (CToken cBAT TotalBorrows) 51e18 + -- Check user liquidity and verify < 0 + Invariant Remains (Comptroller Liquidity Geoff) -1e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 10e18 BAT cBAT + AllowFailures + Erc20 BAT Pause -- Actually a WBTC token + Liquidate Torrey "->" Geoff 2e18 cBAT "Seizing" cZRX + Assert Revert + + +Test "When seize not allowed due to unlisted collateral" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Invariant Remains (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Invariant Remains (CToken cBAT TotalBorrows) 51e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 10e18 BAT cBAT + Comptroller UnList cZRX -- Mock unlist collateral + AllowFailures + Liquidate Torrey "->" Geoff 2e18 cBAT "Seizing" cZRX + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_COMPTROLLER_REJECTION MARKET_NOT_LISTED + +Test "When seize not allowed due to unlisted borrow" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Invariant Remains (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Invariant Remains (CToken cBAT TotalBorrows) 51e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 10e18 BAT cBAT + Comptroller UnList cBAT -- Mock unlist borrow + AllowFailures + Liquidate Torrey "->" Geoff 2e18 cBAT "Seizing" cZRX + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_COMPTROLLER_REJECTION MARKET_NOT_LISTED + +Test "When seize not allowed due to mismatched comptrollers" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Invariant Remains (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Invariant Remains (CToken cBAT TotalBorrows) 51e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 10e18 BAT cBAT + -- Change the comptroller of cZRX + NewComptroller + From Root (CToken cZRX SetComptroller (Unitroller Address)) + FastForward 100000 Blocks -- To match other comptroller + -- + AllowFailures + Liquidate Torrey "->" Geoff 2e18 cBAT "Seizing" cZRX + Assert Revert "revert token seizure failed" + +Test "When there's insufficient collateral" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 borrowPrice:0.001 mintAmount:1e18 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrows) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Prices is 1:1 and collateral factor is 0.5 + -- thus supplies 100e18 cZRX which gives the user 50e18 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 1e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Invariant Remains (CToken cBAT BorrowBalanceStored Geoff) 51e18 + Invariant Remains (CToken cBAT TotalBorrows) 51e18 + PriceOracle SetPrice cBAT 1.0 -- move price back to 1.0, which will put the account *very underwater* + -- Check user liquidity and verify < 0 + Invariant Remains (Comptroller Liquidity Geoff) -50.5e18 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 10e18 BAT cBAT + AllowFailures + Liquidate Torrey "->" Geoff 2e18 cBAT "Seizing" cZRX + Assert Failure TOKEN_INSUFFICIENT_BALANCE LIQUIDATE_SEIZE_TOO_MUCH diff --git a/spec/scenario/Liquidate.scen.old b/spec/scenario/Liquidate.scen.old new file mode 100644 index 000000000..6e8168ab6 --- /dev/null +++ b/spec/scenario/Liquidate.scen.old @@ -0,0 +1,142 @@ +-- Liquidate Tests + +Test "Supply OMG, Borrow Ether, OMG price crashes, Liquidate Ether" + AddToken OMG + SupportMarket OMG (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Geoff OMG "2.1e18" + Faucet Geoff OMG "2.1e18" + Supply Geoff OMG "2.1e18" + Assert Success + Assert Equal (SupplyBalance Geoff OMG) (Exactly "2.1e18") + AddToken Ether + SupportMarket Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Torrey Ether "5.0e18" + Faucet Torrey Ether "5.0e18" + Supply Torrey Ether "2.0e18" + Assert Equal (BalanceSheetSupply OMG) (Exactly "2.1e18") + Assert Equal (TokenBalance Geoff Ether) (Exactly "0.0e18") + EnterMarkets Geoff Ether + Borrow Geoff Ether "1e18" + Assert Success + Assert Equal (BalanceSheetBorrow Ether) (Exactly "1.05e18") -- includes origination fee + Assert Equal (BorrowBalance Geoff Ether) (Exactly "1.05e18") -- includes origination fee + Assert Equal (TokenBalance Geoff Ether) (Exactly "1e18") -- does not include origination fee + -- + -- Ether total supply unchanged + Assert Equal (BalanceSheetSupply Ether) (Exactly "2.0e18") + -- + -- Crash OMG price and liquidate + SetMarketPriceOracle OMG (FixedPrice "0.5") -- Max liquidate at this price should be maxClose = 1E for all the supply + Liquidate Torrey Geoff Ether "1e18" OMG + Assert Success + Assert Equal (BalanceSheetBorrow Ether) (Exactly "0.05e18") -- borrow was paid by liquidator + Assert Equal (BorrowBalance Geoff Ether) (Exactly "0.05e18") -- target user should have liquidated amount closed on borrow + Assert Equal (BalanceSheetSupply OMG) (Exactly "2.1e18") + Assert Equal (SupplyBalance Geoff OMG) (Exactly "0e18") -- Collateral was the limit in this scenario + Assert Equal (TokenBalance Torrey Ether) (Exactly "2.0e18") -- liquidator token balance should be reduced + Assert Equal (TokenBalance Torrey OMG) (Exactly "0e18") + Assert Equal (SupplyBalance Torrey OMG) (Exactly "2.1e18") -- Liquidator now has seized collateral + +Test "Supply OMG, Borrow Ether, gain interest, OMG price crashes, Liquidate Ether" + AddToken OMG + SupportMarket OMG (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Geoff OMG "2.1e18" + Faucet Geoff OMG "2.1e18" + Supply Geoff OMG "2.1e18" + Assert Success + Assert Equal (SupplyBalance Geoff OMG) (Exactly "2.1e18") + AddToken Ether + SupportMarket Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Torrey Ether "20.0e18" + Faucet Torrey Ether "20.0e18" + Supply Torrey Ether "10.0e18" + Assert Equal (BalanceSheetSupply OMG) (Exactly "2.1e18") + Assert Equal (TokenBalance Geoff Ether) (Exactly "0.0e18") + EnterMarkets Geoff Ether + Borrow Geoff Ether "1e18" + Assert Success + Assert Equal (BalanceSheetBorrow Ether) (Exactly "1.05e18") -- includes origination fee + Assert Equal (BorrowBalance Geoff Ether) (Exactly "1.05e18") + Assert Equal (TokenBalance Geoff Ether) (Exactly "1e18") -- does not include origination fee + FastForward 2 Blocks + -- + -- Crash OMG price and liquidate + SetMarketPriceOracle OMG (FixedPrice "0.8") -- Max liquidate at this price should be maxClose ~ 1.98947 E to meet collateral ratio + Liquidate Torrey Geoff Ether "2e18" OMG + Assert Failure INVALID_CLOSE_AMOUNT_REQUESTED LIQUIDATE_CLOSE_AMOUNT_TOO_HIGH + Liquidate Torrey Geoff Ether "1.5e18" OMG + Assert Success + Assert Equal (BalanceSheetBorrow Ether) (Exactly "1.125e18") -- (1.05) * ( 1 + 2 * .75 ) - 1.5 + Assert Equal (BalanceSheetSupply OMG) (Exactly "4.2e18") + Assert Equal (BorrowBalance Geoff Ether) (Exactly "1.125e18") + Assert Equal (SupplyBalance Geoff OMG) (Exactly "2.23125e18") -- (2.1) * (1 + 2 * .5) - 1.96875 [amountSeize] + Assert Equal (TokenBalance Torrey Ether) (Exactly "8.5e18") + Assert Equal (SupplyBalance Torrey Ether) (Exactly "20e18") -- (10) * (1 + 2 * .5) + Assert Equal (TokenBalance Torrey OMG) (Exactly "0e18") + Assert Equal (SupplyBalance Torrey OMG) (Exactly "1.96875e18") + +Test "Can't liquidate when contract is borrow asset is paused" + AddToken OMG + SupportMarket OMG (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Geoff OMG "2.1e18" + Faucet Geoff OMG "2.1e18" + Supply Geoff OMG "2.1e18" + Assert Success + Assert Equal (SupplyBalance Geoff OMG) (Exactly "2.1e18") + AddToken Ether + SupportMarket Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Torrey Ether "5.0e18" + Faucet Torrey Ether "5.0e18" + Supply Torrey Ether "2.0e18" + Assert Equal (BalanceSheetSupply OMG) (Exactly "2.1e18") + Assert Equal (TokenBalance Geoff Ether) (Exactly "0.0e18") + EnterMarkets Geoff Ether + Borrow Geoff Ether "1e18" + Assert Success + Assert Equal (BalanceSheetBorrow Ether) (Exactly "1.05e18") -- includes origination fee + Assert Equal (BorrowBalance Geoff Ether) (Exactly "1.05e18") -- includes origination fee + Assert Equal (TokenBalance Geoff Ether) (Exactly "1e18") -- does not include origination fee + -- + -- Ether total supply unchanged + Assert Equal (BalanceSheetSupply Ether) (Exactly "2.0e18") + -- + -- Crash OMG price and liquidate + SetMarketPriceOracle OMG (FixedPrice "0.5") -- Max liquidate at this price should be maxClose = 1E for all the supply + PolicyHook Ether (SetPaused True) + Liquidate Torrey Geoff Ether "1e18" OMG + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_POLICY_HOOK_ASSET_BORROW_REJECTION 1 + Assert Equal (BalanceSheetBorrow Ether) (Exactly "1.05e18") -- unchanged + Assert Equal (BorrowBalance Geoff Ether) (Exactly "1.05e18") -- unchanged + +Test "Can't liquidate when contract is collateral asset is paused" + AddToken OMG + SupportMarket OMG (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Geoff OMG "2.1e18" + Faucet Geoff OMG "2.1e18" + Supply Geoff OMG "2.1e18" + Assert Success + Assert Equal (SupplyBalance Geoff OMG) (Exactly "2.1e18") + AddToken Ether + SupportMarket Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Torrey Ether "5.0e18" + Faucet Torrey Ether "5.0e18" + Supply Torrey Ether "2.0e18" + Assert Equal (BalanceSheetSupply OMG) (Exactly "2.1e18") + Assert Equal (TokenBalance Geoff Ether) (Exactly "0.0e18") + EnterMarkets Geoff OMG Ether + Borrow Geoff Ether "1e18" + Assert Success + Assert Equal (BalanceSheetBorrow Ether) (Exactly "1.05e18") -- includes origination fee + Assert Equal (BorrowBalance Geoff Ether) (Exactly "1.05e18") -- includes origination fee + Assert Equal (TokenBalance Geoff Ether) (Exactly "1e18") -- does not include origination fee + -- + -- Ether total supply unchanged + Assert Equal (BalanceSheetSupply Ether) (Exactly "2.0e18") + -- + -- Crash OMG price and liquidate + SetMarketPriceOracle OMG (FixedPrice "0.5") -- Max liquidate at this price should be maxClose = 1E for all the supply + PolicyHook OMG (SetPaused True) + Liquidate Torrey Geoff Ether "1e18" OMG + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_POLICY_HOOK_ASSET_COLLATERAL_REJECTION 1 + Assert Equal (BalanceSheetBorrow Ether) (Exactly "1.05e18") -- unchanged + Assert Equal (BorrowBalance Geoff Ether) (Exactly "1.05e18") -- unchanged diff --git a/spec/scenario/LiquidateEthBorrow.scen b/spec/scenario/LiquidateEthBorrow.scen new file mode 100644 index 000000000..dd4657dbe --- /dev/null +++ b/spec/scenario/LiquidateEthBorrow.scen @@ -0,0 +1,138 @@ +Macro NewBorrow borrowAmount borrowRate user=Geoff + PricedComptroller 0.5 20 + Comptroller LiquidationIncentive 1.1 + ListedCToken BAT cBAT + ListedEtherToken cETH initialExchangeRate:0.05e9 + PriceOracle SetPrice cBAT 0.001 + SetCollateralFactor cBAT collateralFactor:0.5 + Donate cETH 0.001e18 + SimpleBorrow user borrowAmount + +Macro SimpleBorrow user borrowAmount + Prep user 100e18 BAT cBAT + Mint user 100e18 cBAT + EnterMarkets user cETH cBAT + Assert Equal (Comptroller Liquidity Geoff) 0.05e18 + Expect Changes (EtherBalance user) +0.001e18 + Expect Changes (EtherBalance cETH) -0.001e18 + BorrowEth user borrowAmount cETH + +Test "Insufficient shortfall" + NewBorrow borrowAmount:0.001e18 borrowRate:0.0005 + Assert Equal (CToken cETH BorrowBalance Geoff) 0.001e18 + Assert Equal (CToken cETH TotalBorrows) 0.001e18 + -- Prices is 1:1000 and collateral factor is 0.5 + -- thus supplies 100.0e18 cBAT which gives the user (0.5 * 100.0e18 * 1.0e-3)=0.05e18 + -- capacity of Eth. User only borrowed 0.001e18, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 98000 Blocks -- 0.001e18 * (1 + 98000 * 0.0005) + AccrueInterest cETH -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cETH BorrowBalanceStored Geoff) 0.05e18 + Assert Equal (CToken cETH TotalBorrows) 0.05e18 + -- Check user liquidity and verify equals 0 + -- At exactly zero, should not be able to liquidate + AllowFailures + Invariant Remains (Comptroller Liquidity Geoff) 0e18 + Invariant Static (EtherBalance Geoff) + Invariant Static (EtherBalance Torrey) + LiquidateEthBorrow Torrey "->" Geoff 10e18 cETH "Seizing" cBAT + Assert RevertFailure COMPTROLLER_REJECTION "revert liquidateBorrow failed" + +Test "Cannot self-liquidate" + NewBorrow borrowAmount:0.001e18 borrowRate:0.0005 + Assert Equal (CToken cETH BorrowBalance Geoff) 0.001e18 + Assert Equal (CToken cETH TotalBorrows) 0.001e18 + -- Prices is 1:1000 and collateral factor is 0.5 + -- thus supplies 100.0e18 cBAT which gives the user (0.5 * 100.0e18 * 1.0e-3)=0.05e18 + -- capacity of Eth. User only borrowed 0.001e18, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 0.001e18 * (1 + 100000 * 0.0005) + AccrueInterest cETH -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cETH BorrowBalanceStored Geoff) 0.051e18 + Assert Equal (CToken cETH TotalBorrows) 0.051e18 + -- Check user liquidity and verify < 0 + -- ( 0.5 * 100e18 * 1e-3 ) - ( 0.051e18 * 1.0 ) = -0.001e18 + Assert Equal (Comptroller Liquidity Geoff) -0.001e18 + -- Okay, so we should be able to liquidate, so let's do that. + AllowFailures + Invariant Remains (Comptroller Liquidity Geoff) -0.001e18 + Invariant Static (EtherBalance Geoff) + LiquidateEthBorrow Geoff "->" Geoff 0.002e18 cETH "Seizing" cBAT + Assert RevertFailure INVALID_ACCOUNT_PAIR "revert liquidateBorrow failed" + +Test "Liqidate beyond max close" + NewBorrow borrowAmount:0.001e18 borrowRate:0.0005 + Assert Equal (CToken cETH BorrowBalance Geoff) 0.001e18 + Assert Equal (CToken cETH TotalBorrows) 0.001e18 + -- Prices is 1:1000 and collateral factor is 0.5 + -- thus supplies 100.0e18 cBAT which gives the user (0.5 * 100.0e18 * 1.0e-3)=0.05e18 + -- capacity of Eth. User only borrowed 0.001e18, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 0.001e18 * (1 + 100000 * 0.0005) + AccrueInterest cETH -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cETH BorrowBalanceStored Geoff) 0.051e18 + Assert Equal (CToken cETH TotalBorrows) 0.051e18 + -- Check user liquidity and verify < 0 + -- ( 0.5 * 100e18 * 1e-3 ) - ( 0.051e18 * 1.0 ) = -0.001e18 + Assert Equal (Comptroller Liquidity Geoff) -0.001e18 + -- Okay, so we should be able to liquidate, so let's do that. + AllowFailures + Invariant Remains (Comptroller Liquidity Geoff) -0.001e18 + Invariant Static (EtherBalance Geoff) + Invariant Static (EtherBalance Torrey) + LiquidateEthBorrow Torrey "->" Geoff 0.04e18 cETH "Seizing" cBAT + Assert RevertFailure COMPTROLLER_REJECTION "revert liquidateBorrow failed" + +Test "Proper liquidation" + NewBorrow borrowAmount:0.001e18 borrowRate:0.0005 + Assert Equal (CToken cETH BorrowBalance Geoff) 0.001e18 + Assert Equal (CToken cETH TotalBorrows) 0.001e18 + -- Prices is 1:1000 and collateral factor is 0.5 + -- thus supplies 100.0e18 cBAT which gives the user (0.5 * 100.0e18 * 1.0e-3)=0.05e18 + -- capacity of Eth. User only borrowed 0.001e18, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 0.001e18 * (1 + 100000 * 0.0005) + AccrueInterest cETH -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cETH BorrowBalanceStored Geoff) 0.051e18 + Assert Equal (CToken cETH TotalBorrows) 0.051e18 + -- Check user liquidity and verify < 0 + -- ( 0.5 * 100e18 * 1e-3 ) - ( 0.051e18 * 1.0 ) = -0.001e18 + Assert Equal (Comptroller Liquidity Geoff) -0.001e18 + -- Okay, so we should be able to liquidate, so let's do that. + -- + -- Let's check how values start before liqudation + -- Note: we're going to be some-what exhausive in what we check + Invariant Static (EtherBalance Geoff) -- ether balance stays the same for borrower + Expect Changes (EtherBalance Torrey) -0.02e18 -- for the repay behalf + Expect Changes (EtherBalance cETH) +0.02e18 -- receives repay + Assert Equal (Erc20 cBAT TokenBalance Geoff) 500e8 -- from minting (100e18 / 2e9) + Expect Changes (Erc20 cBAT TokenBalance Geoff) -110e8 -- from seize loss + Assert Equal (Erc20 cBAT TokenBalance Torrey) 0e9 -- never had any + Expect Changes (Erc20 cBAT TokenBalance Torrey) +110e8 -- from seize gain + Invariant Remains (Erc20 cETH TokenBalance Geoff) 0e8 -- never had any (has underlying) + Invariant Remains (Erc20 cETH TokenBalance Torrey) 0e8 -- never had any + Assert Equal (CToken cETH BorrowBalanceStored Geoff) 0.051e18 -- all that interest + Assert Equal (CToken cETH TotalBorrows) 0.051e18 -- all those borrowers + Assert Equal (Comptroller Liquidity Geoff) -0.001e18 -- underwater + -- + -- Do the liquidation + LiquidateEthBorrow Torrey "->" Geoff 0.02e18 cETH "Seizing" cBAT + -- + -- And see what they are now + Assert Equal (Erc20 cBAT TokenBalance Torrey) 110e8 -- 0.02e18 * (1/1.0e-3) * 1.1 / 2e9 [exchange rate] = 110e8 -> Torrey + Assert Equal (Erc20 cBAT TokenBalance Geoff) 390e8 + Assert Equal (CToken cETH BorrowBalanceStored Geoff) 0.031e18 -- less closed amount + Assert Equal (CToken cETH TotalBorrows) 0.031e18 -- + -- TODO:! + -- User now has 390e18 cBAT outstanding supply + -- capacity. The user also has a 0.031e18 borrow cETH outstanding. + -- ( 0.5 * 390e8 * 2e9 * 0.001 ) - ( 0.031e18 * 1.0 ) = 0.008e18 + Assert Equal (Comptroller Liquidity Geoff) 0.008e18 diff --git a/spec/scenario/LiquidateEthCollateral.scen b/spec/scenario/LiquidateEthCollateral.scen new file mode 100644 index 000000000..cad8400fb --- /dev/null +++ b/spec/scenario/LiquidateEthCollateral.scen @@ -0,0 +1,140 @@ +Macro NewBorrow borrowAmount user=Geoff + PricedComptroller 0.1 20 + Comptroller LiquidationIncentive 1.1 + ListedCToken BAT cBAT borrowRate:0.0005 + ListedEtherToken cETH initialExchangeRate:0.05e9 + PriceOracle SetPrice cBAT 0.001 + Give cBAT 10e18 BAT + Comptroller SetCollateralFactor cETH 0.5 + SimpleBorrow user borrowAmount + +Macro SimpleBorrow user borrowAmount + CallMintEth user 0.001e18 cETH + EnterMarkets user cETH cBAT + Borrow user borrowAmount cBAT + +Test "Insufficient shortfall" + NewBorrow borrowAmount:0.01e18 + Assert Equal (CToken cBAT BorrowBalance Geoff) 0.01e18 + Assert Equal (CToken cBAT TotalBorrows) 0.01e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 0.01e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9.99e18 + -- Prices is 1:1.0e-3 and collateral factor is 0.5 + -- thus supplies 1e15 cETH which gives the user (0.5 x 1.0e15 ÷ 1.0e-3)=0.5 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 98000 Blocks -- 0.01e18 * (1 + 98000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 0.5e18 + Assert Equal (CToken cBAT TotalBorrows) 0.5e18 + -- Check user liquidity and verify equals 0 + Assert Equal (Comptroller Liquidity Geoff) 0e18 + -- At exactly zero, should not be able to liquidate + Prep Torrey 10e18 BAT cBAT + AllowFailures + Liquidate Torrey "->" Geoff 10e18 cBAT "Seizing" cETH + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_COMPTROLLER_REJECTION INSUFFICIENT_SHORTFALL + +Test "Cannot self-liquidate" + NewBorrow borrowAmount:0.01e18 + Assert Equal (CToken cBAT BorrowBalance Geoff) 0.01e18 + Assert Equal (CToken cBAT TotalBorrows) 0.01e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 0.01e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9.99e18 + -- Prices is 1:1.0e-3 and collateral factor is 0.5 + -- thus supplies 1e15 cETH which gives the user (0.5 x 1.0e15 ÷ 1.0e-3)=0.5 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 0.01e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 0.51e18 + Assert Equal (CToken cBAT TotalBorrows) 0.51e18 + -- Check user liquidity and verify < 0 + -- ( 0.5 * 1.0e15 ) - ( 0.51e18 * 1.0e-3 ) = -1e13 + Assert Equal (Comptroller Liquidity Geoff) -1e13 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Geoff 10e18 BAT cBAT + AllowFailures + Liquidate Geoff "->" Geoff 0.02e18 cBAT "Seizing" cETH + Assert Failure INVALID_ACCOUNT_PAIR LIQUIDATE_LIQUIDATOR_IS_BORROWER + +Test "Liqidate beyond max close" + NewBorrow borrowAmount:0.01e18 + Assert Equal (CToken cBAT BorrowBalance Geoff) 0.01e18 + Assert Equal (CToken cBAT TotalBorrows) 0.01e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 0.01e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9.99e18 + -- Prices is 1:1.0e-3 and collateral factor is 0.5 + -- thus supplies 1e15 cETH which gives the user (0.5 x 1.0e15 ÷ 1.0e-3)=0.5 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 0.01e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 0.51e18 + Assert Equal (CToken cBAT TotalBorrows) 0.51e18 + -- Check user liquidity and verify < 0 + -- ( 0.5 * 1.0e15 ) - ( 0.51e18 * 1.0e-3 ) = -1e13 + Assert Equal (Comptroller Liquidity Geoff) -1e13 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 10e18 BAT cBAT + AllowFailures + Liquidate Torrey "->" Geoff 0.2e18 cBAT "Seizing" cETH + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_COMPTROLLER_REJECTION TOO_MUCH_REPAY + +Test "Proper liquidation" + NewBorrow borrowAmount:0.01e18 + Assert Equal (CToken cBAT BorrowBalance Geoff) 0.01e18 + Assert Equal (CToken cBAT TotalBorrows) 0.01e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 0.01e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9.99e18 + -- Prices is 1:1.0e-3 and collateral factor is 0.5 + -- thus supplies 1e15 cETH which gives the user (0.5 x 1.0e15 ÷ 1.0e-3)=0.5 + -- capacity of BAT. User only borrowed 1BAT, but after + -- a few blocks at a 50% interest rate, he'll be + -- underwater. + FastForward 100000 Blocks -- 0.01e18 * (1 + 100000 * 0.0005) + AccrueInterest cBAT -- Note: we have to accrue interest + -- since it's not automatic for liquidity + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 0.51e18 + Assert Equal (CToken cBAT TotalBorrows) 0.51e18 + -- Check user liquidity and verify < 0 + -- ( 0.5 * 1.0e15 ) - ( 0.51e18 * 1.0e-3 ) = -1e13 + Assert Equal (Comptroller Liquidity Geoff) -1e13 + -- Okay, so we should be able to liquidate, so let's do that. + Prep Torrey 0.02e18 BAT cBAT + -- + -- Let's check how values start before liqudation + -- Note: we're going to be some-what exhausive in what we check + Invariant Static (EtherBalance Geoff) -- ether balance stays the same + Invariant Static (EtherBalance Torrey) -- + Invariant Static (EtherBalance cETH) -- + Assert Equal (Erc20 cETH TokenBalance Geoff) 0.2e8 -- from minting (0.001e18 / 0.05e9) + Assert Equal (Erc20 cETH TokenBalance Torrey) 0e9 -- never had any + Invariant Remains (Erc20 BAT TokenBalance Geoff) 0.01e18 -- original amount borrowed + Assert Equal (Erc20 BAT TokenBalance Torrey) 0.02e18 -- from prep above + Assert Equal (Erc20 BAT TokenBalance cBAT) 9.99e18 -- had 10e18, lent 0.01e18 to geoff + Invariant Remains (Erc20 cBAT TokenBalance Geoff) 0e8 -- never had any (has underlying) + Invariant Remains (Erc20 cBAT TokenBalance Torrey) 0e8 -- never had any + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 0.51e18 -- all that interest + Assert Equal (CToken cBAT TotalBorrows) 0.51e18 -- all those borrowers + Assert Equal (Comptroller Liquidity Geoff) -1e13 -- underwater + -- Do the liquidation + LiquidateEthColl Torrey "->" Geoff 0.02e18 cBAT "Seizing" cETH + -- + -- And see what they are now + Assert Equal (Erc20 cETH TokenBalance Torrey) 0.0044e8 -- 0.02e18 * (1.0e-3/1) * 1.1 / 0.05e9 [exchange rate] = 0.0044e8 -> Torrey + Assert Equal (Erc20 cETH TokenBalance Geoff) 0.1956e8 + Assert Equal (Erc20 BAT TokenBalance Torrey) 0e18 -- repaid + Assert Equal (Erc20 BAT TokenBalance cBAT) 10.01e18 -- had 10e18, lent 0.01e18 to geoff, repaid 0.02 + Assert Equal (CToken cBAT BorrowBalanceStored Geoff) 0.49e18 -- less closed amount + Assert Equal (CToken cBAT TotalBorrows) 0.49e18 -- + -- User now has 0.1956 cETH outstanding supply + -- capacity. The user also has a 0.49e18 borrow BAT outstanding. + -- ( 0.5 * 0.1956e8 * 0.05e9 * 1.0 ) - ( 0.49e18 * 1.0e-3 ) = 0.09731e18 + Assert Equal (Comptroller Liquidity Geoff) -0.000001e18 diff --git a/spec/scenario/Mint.scen b/spec/scenario/Mint.scen new file mode 100644 index 000000000..e00130923 --- /dev/null +++ b/spec/scenario/Mint.scen @@ -0,0 +1,90 @@ +-- Mint Tests + +Test "Mint 1 cZRX" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff Some ZRX cZRX + Mint Geoff 50e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 50e9) + -- Assert Equal (CToken cZRX UnderlyingBalance Geoff) (Exactly 1.0e18) + +Test "Mint with insufficient allowance" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 49e18 ZRX cZRX + AllowFailures + Mint Geoff 50e18 cZRX + Assert Failure TOKEN_INSUFFICIENT_ALLOWANCE MINT_TRANSFER_IN_NOT_POSSIBLE + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 0e9) + +Test "Mint with insufficient balance" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 49e18 ZRX cZRX allowanceAmount:50e18 + AllowFailures + Mint Geoff 50e18 cZRX + Assert Failure TOKEN_INSUFFICIENT_BALANCE MINT_TRANSFER_IN_NOT_POSSIBLE + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 0e9) + +Test "Mint two ZRX after minting two ZRX, and then I mint two more" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff Some ZRX cZRX + Mint Geoff 2e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 2e9) + Assert Equal (Erc20 cZRX TotalSupply) (Exactly 2e9) + Mint Geoff 2e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 4e9) + Assert Equal (Erc20 cZRX TotalSupply) (Exactly 4e9) + Mint Geoff 2e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 6e9) + Assert Equal (Erc20 cZRX TotalSupply) (Exactly 6e9) + +Test "Two users Mint" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff Some ZRX cZRX + Prep Torrey Some ZRX cZRX + Mint Geoff 2e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 2e9) + Assert Equal (Erc20 cZRX TotalSupply) (Exactly 2e9) + Mint Torrey 2e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 2e9) + Assert Equal (Erc20 cZRX TokenBalance Torrey) (Exactly 2e9) + Assert Equal (Erc20 cZRX TotalSupply) (Exactly 4e9) + +Test "Mint accrues no interest without borrows" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff Some ZRX cZRX + Prep Torrey Some ZRX cZRX + Mint Geoff 2e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 2e9) + Assert Equal (Erc20 cZRX TotalSupply) (Exactly 2e9) + FastForward 1000 Blocks + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 2e9) + Assert Equal (Erc20 cZRX TotalSupply) (Exactly 2e9) + +Test "Mint transfer in fails" + NewComptroller + ListedCToken EVL cEVL tokenType:Evil + Prep Geoff Some EVL cEVL + Prep Torrey Some EVL cEVL + Invariant Static (Erc20 cEVL TokenBalance Geoff) + Invariant Static (Erc20 cEVL TotalSupply) + Invariant Static (Erc20 EVL TotalSupply) + AllowFailures + Mint Geoff 2e18 cEVL + Assert Failure TOKEN_TRANSFER_IN_FAILED MINT_TRANSFER_IN_FAILED + +Test "Denied by comptroller because unlisted" + NewComptroller + NewCToken ZRX cZRX + Prep Geoff Some ZRX cZRX + Prep Torrey Some ZRX cZRX + Invariant Static (Erc20 cZRX TokenBalance Geoff) + Invariant Static (Erc20 cZRX TotalSupply) + Invariant Static (Erc20 ZRX TotalSupply) + AllowFailures + Mint Geoff 2e18 cZRX + Assert Failure COMPTROLLER_REJECTION MINT_COMPTROLLER_REJECTION MARKET_NOT_LISTED diff --git a/spec/scenario/MintEth.scen b/spec/scenario/MintEth.scen new file mode 100644 index 000000000..922c7ea82 --- /dev/null +++ b/spec/scenario/MintEth.scen @@ -0,0 +1,66 @@ +-- Mint Tests + +GasTest "Send Mint 1 cETH" + NewComptroller + ListedEtherTokenMinted cETH initialExchangeRate:0.005e9 + Expect Changes (EtherBalance Geoff) -0.005e18 + Expect Changes (CToken cETH UnderlyingBalance Geoff) +0.005e18 + SendMintEth Geoff 0.005e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 10e8 + Assert LastGas LessThan 90e3 + +GasTest "Call Mint 1 cETH" + NewComptroller + ListedEtherTokenMinted cETH initialExchangeRate:0.005e9 + Expect Changes (EtherBalance Geoff) -0.005e18 + Expect Changes (CToken cETH UnderlyingBalance Geoff) +0.005e18 + CallMintEth Geoff 0.005e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 10e8 + Assert LastGas LessThan 90e3 + +Test "Mint with insufficient eth balance" + NewComptroller + ListedEtherTokenMinted cETH initialExchangeRate:0.005e9 + AllowFailures + Invariant Remains (CToken cETH UnderlyingBalance Geoff) 0e18 + Invariant Remains (Erc20 cETH TokenBalance Geoff) 0e8 + Invariant Static (EtherBalance Geoff) + CallMintEth Geoff 1e30 cETH + Assert Error "Returned error: sender doesn't have enough funds to send tx" + +Test "Mint two Eth after minting two Eth, and then I mint two more" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + Expect Changes (EtherBalance Geoff) -0.002e18 + CallMintEth Geoff 0.002e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 4e8 + Assert Equal (Erc20 cETH TotalSupply) 4e8 + Expect Changes (EtherBalance Geoff) -0.002e18 + SendMintEth Geoff 0.002e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 8e8 + Assert Equal (Erc20 cETH TotalSupply) 8e8 + Expect Changes (EtherBalance Geoff) -0.002e18 + CallMintEth Geoff 0.002e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 12e8 + Assert Equal (Erc20 cETH TotalSupply) 12e8 + +Test "Two users Mint" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + CallMintEth Geoff 0.002e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 4e8 + Assert Equal (Erc20 cETH TotalSupply) 4e8 + CallMintEth Torrey 0.004e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 4e8 + Assert Equal (Erc20 cETH TokenBalance Torrey) 8e8 + Assert Equal (Erc20 cETH TotalSupply) 12e8 + +Test "Mint accrues no interest without borrows" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + CallMintEth Geoff 0.002e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 4e8 + Assert Equal (Erc20 cETH TotalSupply) 4e8 + FastForward 1000 Blocks + Assert Equal (Erc20 cETH TokenBalance Geoff) 4e8 + Assert Equal (Erc20 cETH TotalSupply) 4e8 diff --git a/spec/scenario/MintWBTC.scen b/spec/scenario/MintWBTC.scen new file mode 100644 index 000000000..89159cdf4 --- /dev/null +++ b/spec/scenario/MintWBTC.scen @@ -0,0 +1,91 @@ +-- Mint Tests + +Test "Mint 1 cWBTC" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.2 tokenType:WBTC + Prep Geoff Some WBTC cWBTC + Mint Geoff 10e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) (Exactly 50e8) + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) (Exactly 10e8) + +Test "Mint WBTC with insufficient allowance" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.2 tokenType:WBTC + Prep Geoff 4.9e8 WBTC cWBTC + AllowFailures + Mint Geoff 5e8 cWBTC + Assert Failure TOKEN_INSUFFICIENT_ALLOWANCE MINT_TRANSFER_IN_NOT_POSSIBLE + Assert Equal (Erc20 cWBTC TokenBalance Geoff) (Exactly 0e8) + +Test "Mint WBTC with insufficient balance" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.2 tokenType:WBTC + Prep Geoff 4.9e8 WBTC cWBTC allowanceAmount:5e8 + AllowFailures + Mint Geoff 5e8 cWBTC + Assert Failure TOKEN_INSUFFICIENT_BALANCE MINT_TRANSFER_IN_NOT_POSSIBLE + Assert Equal (Erc20 cWBTC TokenBalance Geoff) (Exactly 0e8) + +Test "Mint two WBTC after minting two WBTC, and then I mint two more" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.2 tokenType:WBTC + Prep Geoff Some WBTC cWBTC + Mint Geoff 2e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) (Exactly 10e8) + Assert Equal (Erc20 cWBTC TotalSupply) (Exactly 10e8) + Mint Geoff 2e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) (Exactly 20e8) + Assert Equal (Erc20 cWBTC TotalSupply) (Exactly 20e8) + Mint Geoff 2e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) (Exactly 30e8) + Assert Equal (Erc20 cWBTC TotalSupply) (Exactly 30e8) + +Test "Two users Mint WBTC" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.2 tokenType:WBTC + Prep Geoff Some WBTC cWBTC + Prep Torrey Some WBTC cWBTC + Mint Geoff 2e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) (Exactly 10e8) + Assert Equal (Erc20 cWBTC TotalSupply) (Exactly 10e8) + Mint Torrey 2e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) (Exactly 10e8) + Assert Equal (Erc20 cWBTC TokenBalance Torrey) (Exactly 10e8) + Assert Equal (Erc20 cWBTC TotalSupply) (Exactly 20e8) + +Test "Mint WBTC accrues no interest without borrows" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.2 tokenType:WBTC + Prep Geoff Some WBTC cWBTC + Prep Torrey Some WBTC cWBTC + Mint Geoff 2e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) (Exactly 10e8) + Assert Equal (Erc20 cWBTC TotalSupply) (Exactly 10e8) + FastForward 1000 Blocks + Assert Equal (Erc20 cWBTC TokenBalance Geoff) (Exactly 10e8) + Assert Equal (Erc20 cWBTC TotalSupply) (Exactly 10e8) + +Test "Mint WBTC transfer in fails due to paused" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.2 tokenType:WBTC + Prep Geoff Some WBTC cWBTC + Prep Torrey Some WBTC cWBTC + Invariant Static (Erc20 cWBTC TokenBalance Geoff) + Invariant Static (Erc20 cWBTC TotalSupply) + Invariant Static (Erc20 WBTC TotalSupply) + Erc20 WBTC Pause + AllowFailures + Mint Geoff 2e8 cWBTC + Assert Revert + +Test "Denied by comptroller because WBTC unlisted" + NewComptroller + NewCToken WBTC cWBTC tokenType:WBTC + Prep Geoff Some WBTC cWBTC + Prep Torrey Some WBTC cWBTC + Invariant Static (Erc20 cWBTC TokenBalance Geoff) + Invariant Static (Erc20 cWBTC TotalSupply) + Invariant Static (Erc20 WBTC TotalSupply) + AllowFailures + Mint Geoff 2e8 cWBTC + Assert Failure COMPTROLLER_REJECTION MINT_COMPTROLLER_REJECTION MARKET_NOT_LISTED diff --git a/spec/scenario/ReEntry.scen b/spec/scenario/ReEntry.scen new file mode 100644 index 000000000..1152a1174 --- /dev/null +++ b/spec/scenario/ReEntry.scen @@ -0,0 +1,13 @@ +-- Mint Tests + +Test "ReEntry Mint" + NewComptroller + Erc20 Deploy ReEntrant PHREAK PHREAK "transferFrom" "mint(uint256)" "0" + InterestRateModel Deploy Fixed Std 0.0001 + CToken Deploy cPHREAK cPHREAK (Erc20 PHREAK Address) (Comptroller Address) (InterestRateModel Std Address) 1e9 8 + Comptroller SupportMarket cPHREAK + Prep Geoff Some PHREAK cPHREAK + AllowFailures + Mint Geoff 50e18 cPHREAK + Assert Revert "revert re-entered" + Assert Equal (Erc20 cPHREAK TokenBalance Geoff) Zero diff --git a/spec/scenario/Redeem.scen b/spec/scenario/Redeem.scen new file mode 100644 index 000000000..2dd24ec25 --- /dev/null +++ b/spec/scenario/Redeem.scen @@ -0,0 +1,227 @@ +-- Redeem Tests + +Test "Mint then Redeem All" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 70e18 ZRX cZRX + Mint Geoff 50e18 cZRX + -- Check current affairs + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (Erc20 ZRX TokenBalance Geoff) 20e18 + -- Any other good invariants? + Invariant Static (CToken cZRX ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + Redeem Geoff 500e8 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) Zero + Assert Equal (Erc20 ZRX TokenBalance Geoff) 70e18 + +Test "Mint, Enter and then Redeem All" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 70e18 ZRX cZRX + Mint Geoff 50e18 cZRX + -- Check current affairs + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (Erc20 ZRX TokenBalance Geoff) 20e18 + -- Any other good invariants? + Invariant Static (CToken cZRX ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + EnterMarkets Geoff cZRX + Redeem Geoff 500e8 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) Zero + Assert Equal (Erc20 ZRX TokenBalance Geoff) 70e18 + +Test "Mint then Redeem Part" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 70e18 ZRX cZRX + Mint Geoff 50e18 cZRX + -- Check current affairs + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (Erc20 ZRX TokenBalance Geoff) 20e18 + -- Any other good invariants? + Invariant Static (CToken cZRX ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + Redeem Geoff 250e8 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 250e8 + Assert Equal (Erc20 ZRX TokenBalance Geoff) 45e18 + +Test "Mint then Redeem Too Much" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 70e18 ZRX cZRX + Mint Geoff 50e18 cZRX + -- Check and hold static + Invariant Static (CToken cZRX ExchangeRateStored) + Invariant Remains (Erc20 cZRX TokenBalance Geoff) 500e8 + Invariant Remains (Erc20 ZRX TokenBalance Geoff) 20e18 + -- Now redeem after some time + FastForward 2 Blocks + AllowFailures + Redeem Geoff 501e8 cZRX + Assert Failure MATH_ERROR REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED "3" + +Test "Mint then Redeem Zero" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 70e18 ZRX cZRX + Mint Geoff 50e18 cZRX + -- Check current affairs + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (Erc20 ZRX TokenBalance Geoff) 20e18 + -- Any other good invariants? + Invariant Static (CToken cZRX ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + Redeem Geoff 0e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (Erc20 ZRX TokenBalance Geoff) 20e18 + +Test "Mint then redeem with interest - no reserves" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Invariant Remains (CToken cZRX Reserves) Zero + Prep Geoff 50e18 ZRX cZRX + Mint Geoff 50e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 50e18 + Assert Equal (CToken cZRX ExchangeRate) 1e9 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cZRX 10e18 5e18 interestRate:0.0001 blocks:5000 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- This is due pro-rata to all holders, but we just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 55e18 + Assert Equal (CToken cZRX ExchangeRate) 1.1e9 + -- Now redeem all with interest + Redeem Geoff 500e8 cZRX + Assert Equal (Erc20 ZRX TokenBalance Geoff) 55e18 + Assert Equal (Erc20 ZRX TokenBalance cZRX) 0e18 + Assert Equal (Erc20 cZRX TokenBalance Geoff) 0e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 0e18 + Assert Equal (CToken cZRX ExchangeRate) 1e9 + +Test "Mint then redeem part with interest - no reserves" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Invariant Remains (CToken cZRX Reserves) Zero + Prep Geoff 50e18 ZRX cZRX + Mint Geoff 50e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 50e18 + Assert Equal (CToken cZRX ExchangeRate) 1e9 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cZRX 10e18 5e18 interestRate:0.0001 blocks:5000 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- This is due pro-rata to all holders, but we just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 55e18 + Assert Equal (CToken cZRX ExchangeRate) 1.1e9 + -- Now redeem all with interest + Redeem Geoff 499e8 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 1e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 0.11e18 + Assert Equal (CToken cZRX ExchangeRate) 1.1e9 + +Test "Mint then redeem with reserves and interest" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 50e18 ZRX cZRX + Mint Geoff 50e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 50e18 + Assert Equal (CToken cZRX ExchangeRate) 1e9 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cZRX 10e18 5e18 interestRate:0.0001 blocks:5000 reserveRate:0.2 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- The reserves should get 20% of this, or 1e18, and the rest + -- is due pro-rata to all holders. We just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (CToken cZRX Reserves) 1e18 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 54e18 + -- 55e18 + 0e18 - 1e18 / 500 + Assert Equal (CToken cZRX ExchangeRate) 1.08e9 + -- Now redeem all with interest + Redeem Geoff 500e8 cZRX + Assert Equal (Erc20 ZRX TokenBalance Geoff) 54e18 + Assert Equal (Erc20 ZRX TokenBalance cZRX) 1e18 + Assert Equal (Erc20 cZRX TokenBalance Geoff) 0e8 + Assert Equal (CToken cZRX Reserves) 1e18 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 0e18 + Assert Equal (CToken cZRX ExchangeRate) 1e9 + +Test "Two users Mint, one redeems" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff Some ZRX cZRX + Prep Torrey Some ZRX cZRX + Mint Geoff 2e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 20e8 + Assert Equal (Erc20 cZRX TotalSupply) 20e8 + Mint Torrey 2e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 20e8 + Assert Equal (Erc20 cZRX TokenBalance Torrey) 20e8 + Assert Equal (Erc20 cZRX TotalSupply) 40e8 + Redeem Torrey 10e8 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 20e8 + Assert Equal (Erc20 cZRX TokenBalance Torrey) 10e8 + Assert Equal (Erc20 cZRX TotalSupply) 30e8 + +Test "Redeem transfer out fails" + NewComptroller + ListedCToken EVL cEVL initialExchangeRate:1e9 tokenType:Evil + Erc20 EVL SetFail False + Prep Geoff 70e18 EVL cEVL + Mint Geoff 50e18 cEVL + -- Check current affairs + Invariant Remains (Erc20 cEVL TokenBalance Geoff) 500e8 + Invariant Remains (Erc20 EVL TokenBalance Geoff) 20e18 + Invariant Static (CToken cEVL ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + Erc20 EVL SetFail True + AllowFailures + Redeem Geoff 500e8 cEVL + Assert Revert "revert redeem transfer out failed" + +Test "Mint, Enter, then Redeem Too Much (collateral factor: 0)" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 70e18 ZRX cZRX + Mint Geoff 50e18 cZRX + -- Check and hold static + Invariant Static (CToken cZRX ExchangeRateStored) + Invariant Remains (Erc20 cZRX TokenBalance Geoff) 500e8 + Invariant Remains (Erc20 ZRX TokenBalance Geoff) 20e18 + -- Now redeem after some time + FastForward 2 Blocks + EnterMarkets Geoff cZRX + AllowFailures + Redeem Geoff 501e8 cZRX + Assert Failure MATH_ERROR REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED "3" + +Test "Mint, Enter, then Redeem Too Much (collateral factor: 0.1)" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Comptroller SetCollateralFactor cZRX 0.1 + Prep Geoff 70e18 ZRX cZRX + Mint Geoff 50e18 cZRX + -- Check and hold static + Invariant Static (CToken cZRX ExchangeRateStored) + Invariant Remains (Erc20 cZRX TokenBalance Geoff) 500e8 + Invariant Remains (Erc20 ZRX TokenBalance Geoff) 20e18 + -- Now redeem after some time + FastForward 2 Blocks + EnterMarkets Geoff cZRX + AllowFailures + Redeem Geoff 501e8 cZRX + Assert Failure COMPTROLLER_REJECTION REDEEM_COMPTROLLER_REJECTION INSUFFICIENT_LIQUIDITY diff --git a/spec/scenario/RedeemEth.scen b/spec/scenario/RedeemEth.scen new file mode 100644 index 000000000..3985fb686 --- /dev/null +++ b/spec/scenario/RedeemEth.scen @@ -0,0 +1,156 @@ +-- Redeem Tests + +Test "Mint then Redeem All" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + CallMintEth Geoff 0.005e18 cETH + -- Check current affairs + Assert Equal (Erc20 cETH TokenBalance Geoff) 10e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 0.005e18 + Invariant Static (CToken cETH ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + Expect Changes (EtherBalance Geoff) +0.005e18 + RedeemEth Geoff 10e8 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) Zero + Assert Equal (CToken cETH UnderlyingBalance Geoff) Zero + +Test "Mint then Redeem Part" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + CallMintEth Geoff 0.005e18 cETH + -- Check current affairs + Assert Equal (Erc20 cETH TokenBalance Geoff) 10e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 0.005e18 + Invariant Static (CToken cETH ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + Expect Changes (EtherBalance Geoff) +0.001e18 + RedeemEth Geoff 2e8 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 8e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 0.004e18 + +Test "Mint then Redeem Too Much" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + CallMintEth Geoff 0.005e18 cETH + AllowFailures + -- Check and hold static + Invariant Static (CToken cETH ExchangeRateStored) + Invariant Remains (Erc20 cETH TokenBalance Geoff) 10e8 + Invariant Static (EtherBalance Geoff) + -- Now redeem after some time + FastForward 2 Blocks + RedeemEth Geoff 11e8 cETH + -- TODO: This should really be REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, but based on + -- the order of subtractions, total supply comes before account supply. + Assert Failure MATH_ERROR REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED "3" -- TODO: This error is wrong + +Test "Mint then Redeem Zero" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + CallMintEth Geoff 0.005e18 cETH + -- Check and hold static + Invariant Static (CToken cETH ExchangeRateStored) + Invariant Remains (Erc20 cETH TokenBalance Geoff) 10e8 + Invariant Static (EtherBalance Geoff) + -- Now redeem after some time + FastForward 2 Blocks + RedeemEth Geoff 0e9 cETH + +Pending "Mint then redeem with interest - no reserves" + Invariant Success + NewComptroller + ListedCToken ZRX cETH initialExchangeRate:1e9 + Invariant Remains (CToken cETH Reserves) Zero + Prep Geoff 50e18 ZRX cETH + Mint Geoff 50e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 500e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 50e18 + Assert Equal (CToken cETH ExchangeRate) 1e9 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cETH 10e18 5e18 interestRate:0.0001 blocks:5000 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- This is due pro-rata to all holders, but we just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cETH TokenBalance Geoff) 500e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 55e18 + Assert Equal (CToken cETH ExchangeRate) 1.1e9 + -- Now redeem all with interest + Redeem Geoff 500e8 cETH + Assert Equal (Erc20 ZRX TokenBalance Geoff) 55e18 + Assert Equal (Erc20 ZRX TokenBalance cETH) 0e18 + Assert Equal (Erc20 cETH TokenBalance Geoff) 0e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 0e18 + Assert Equal (CToken cETH ExchangeRate) 1e9 + +Pending "Mint then redeem part with interest - no reserves" + Invariant Success + NewComptroller + ListedCToken ZRX cETH initialExchangeRate:1e9 + Invariant Remains (CToken cETH Reserves) Zero + Prep Geoff 50e18 ZRX cETH + Mint Geoff 50e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 500e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 50e18 + Assert Equal (CToken cETH ExchangeRate) 1e9 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cETH 10e18 5e18 interestRate:0.0001 blocks:5000 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- This is due pro-rata to all holders, but we just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cETH TokenBalance Geoff) 500e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 55e18 + Assert Equal (CToken cETH ExchangeRate) 1.1e9 + -- Now redeem all with interest + Redeem Geoff 499e8 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 1e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 0.11e18 + Assert Equal (CToken cETH ExchangeRate) 1.1e9 + +Pending "Mint then redeem with reserves and interest" + Invariant Success + NewComptroller + ListedCToken ZRX cETH initialExchangeRate:1e9 + Prep Geoff 50e18 ZRX cETH + Mint Geoff 50e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 500e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 50e18 + Assert Equal (CToken cETH ExchangeRate) 1e9 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cETH 10e18 5e18 interestRate:0.0001 blocks:5000 reserveRate:0.2 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- The reserves should get 20% of this, or 1e18, and the rest + -- is due pro-rata to all holders. We just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cETH TokenBalance Geoff) 500e8 + Assert Equal (CToken cETH Reserves) 1e18 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 54e18 + -- 55e18 + 0e18 - 1e18 / 500 + Assert Equal (CToken cETH ExchangeRate) 1.08e9 + -- Now redeem all with interest + Redeem Geoff 500e8 cETH + Assert Equal (Erc20 ZRX TokenBalance Geoff) 54e18 + Assert Equal (Erc20 ZRX TokenBalance cETH) 1e18 + Assert Equal (Erc20 cETH TokenBalance Geoff) 0e8 + Assert Equal (CToken cETH Reserves) 1e18 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 0e18 + Assert Equal (CToken cETH ExchangeRate) 1e9 + +Test "Two users Mint, one redeems" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + CallMintEth Geoff 0.002e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 4e8 + Assert Equal (Erc20 cETH TotalSupply) 4e8 + CallMintEth Torrey 0.004e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 4e8 + Assert Equal (Erc20 cETH TokenBalance Torrey) 8e8 + Assert Equal (Erc20 cETH TotalSupply) 12e8 + RedeemEth Torrey 3e8 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 4e8 + Assert Equal (Erc20 cETH TokenBalance Torrey) 5e8 + Assert Equal (Erc20 cETH TotalSupply) 9e8 diff --git a/spec/scenario/RedeemUnderlying.scen b/spec/scenario/RedeemUnderlying.scen new file mode 100644 index 000000000..79143fbb4 --- /dev/null +++ b/spec/scenario/RedeemUnderlying.scen @@ -0,0 +1,182 @@ +-- Redeem Tests + +Test "Mint then Redeem All" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 70e18 ZRX cZRX + Mint Geoff 50e18 cZRX + -- Check current affairs + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (Erc20 ZRX TokenBalance Geoff) 20e18 + -- Any other good invariants? + Invariant Static (CToken cZRX ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + RedeemUnderlying Geoff 50e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) Zero + Assert Equal (Erc20 ZRX TokenBalance Geoff) 70e18 + +Test "Mint then Redeem Part" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 70e18 ZRX cZRX + Mint Geoff 50e18 cZRX + -- Check current affairs + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (Erc20 ZRX TokenBalance Geoff) 20e18 + -- Any other good invariants? + Invariant Static (CToken cZRX ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + RedeemUnderlying Geoff 25e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 250e8 + Assert Equal (Erc20 ZRX TokenBalance Geoff) 45e18 + +Test "Mint then Redeem Too Much" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 70e18 ZRX cZRX + Mint Geoff 50e18 cZRX + -- Check and hold static + Invariant Static (CToken cZRX ExchangeRateStored) + Invariant Remains (Erc20 cZRX TokenBalance Geoff) 500e8 + Invariant Remains (Erc20 ZRX TokenBalance Geoff) 20e18 + -- Now redeem after some time + FastForward 2 Blocks + AllowFailures + RedeemUnderlying Geoff 50.1e18 cZRX + Assert Failure MATH_ERROR REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED "3" + +Test "Mint then Redeem Zero" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 70e18 ZRX cZRX + Mint Geoff 50e18 cZRX + -- Check current affairs + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (Erc20 ZRX TokenBalance Geoff) 20e18 + -- Any other good invariants? + Invariant Static (CToken cZRX ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + RedeemUnderlying Geoff 0e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (Erc20 ZRX TokenBalance Geoff) 20e18 + +Test "Mint then redeem with interest - no reserves" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Invariant Remains (CToken cZRX Reserves) Zero + Prep Geoff 50e18 ZRX cZRX + Mint Geoff 50e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 50e18 + Assert Equal (CToken cZRX ExchangeRate) 1e9 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cZRX 10e18 5e18 interestRate:0.0001 blocks:5000 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- This is due pro-rata to all holders, but we just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 55e18 + Assert Equal (CToken cZRX ExchangeRate) 1.1e9 + -- Now redeem all with interest + -- Exchange rate is now 55e18 ÷ 50e9 = 1.1e9 + -- 500e9 * 1.1e9 = 55e18 + RedeemUnderlying Geoff 55e18 cZRX + Assert Equal (Erc20 ZRX TokenBalance Geoff) 55e18 + Assert Equal (Erc20 ZRX TokenBalance cZRX) 0e18 + Assert Equal (Erc20 cZRX TokenBalance Geoff) 0e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 0e18 + Assert Equal (CToken cZRX ExchangeRate) 1e9 + +Test "Mint then redeem part with interest - no reserves" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Invariant Remains (CToken cZRX Reserves) Zero + Prep Geoff 50e18 ZRX cZRX + Mint Geoff 50e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 50e18 + Assert Equal (CToken cZRX ExchangeRate) 1e9 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cZRX 10e18 5e18 interestRate:0.0001 blocks:5000 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- This is due pro-rata to all holders, but we just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 55e18 + Assert Equal (CToken cZRX ExchangeRate) 1.1e9 + -- Now redeem all with interest + -- Exchange rate is now 55e18 ÷ 50e9 = 1.1e9 + -- 499e9 * 1.1e9 = 54.89e18 + RedeemUnderlying Geoff 54.89e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 1e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 0.11e18 + Assert Equal (CToken cZRX ExchangeRate) 1.1e9 + +Test "Mint then redeem with reserves and interest" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 50e18 ZRX cZRX + Mint Geoff 50e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 50e18 + Assert Equal (CToken cZRX ExchangeRate) 1e9 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cZRX 10e18 5e18 interestRate:0.0001 blocks:5000 reserveRate:0.2 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- The reserves should get 20% of this, or 1e18, and the rest + -- is due pro-rata to all holders. We just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cZRX TokenBalance Geoff) 500e8 + Assert Equal (CToken cZRX Reserves) 1e18 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 54e18 + -- 55e18 + 0e18 - 1e18 / 500 + Assert Equal (CToken cZRX ExchangeRate) 1.08e9 + -- Now redeem all with interest + -- Exchange rate is 1.08e9 + -- 500e8 * 1.08e9 = 54e18 + RedeemUnderlying Geoff 54e18 cZRX + Assert Equal (Erc20 ZRX TokenBalance Geoff) 54e18 + Assert Equal (Erc20 ZRX TokenBalance cZRX) 1e18 + Assert Equal (Erc20 cZRX TokenBalance Geoff) 0e8 + Assert Equal (CToken cZRX Reserves) 1e18 + Assert Equal (CToken cZRX UnderlyingBalance Geoff) 0e18 + Assert Equal (CToken cZRX ExchangeRate) 1e9 + +Test "Two users Mint, one redeems" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff Some ZRX cZRX + Prep Torrey Some ZRX cZRX + Mint Geoff 2e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 20e8 + Assert Equal (Erc20 cZRX TotalSupply) 20e8 + Mint Torrey 2e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 20e8 + Assert Equal (Erc20 cZRX TokenBalance Torrey) 20e8 + Assert Equal (Erc20 cZRX TotalSupply) 40e8 + RedeemUnderlying Torrey 1e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 20e8 + Assert Equal (Erc20 cZRX TokenBalance Torrey) 10e8 + Assert Equal (Erc20 cZRX TotalSupply) 30e8 + +Test "Mint then Redeem 1 wei of underlying" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 70e18 ZRX cZRX + Mint Geoff 50e18 cZRX + AllowFailures + -- Check current affairs + Invariant Remains (Erc20 cZRX TokenBalance Geoff) 500e8 + Invariant Remains (Erc20 ZRX TokenBalance Geoff) 20e18 + -- Any other good invariants? + Invariant Static (CToken cZRX ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + RedeemUnderlying Geoff 1 cZRX + Assert Revert "revert redeemTokens zero" diff --git a/spec/scenario/RedeemUnderlyingEth.scen b/spec/scenario/RedeemUnderlyingEth.scen new file mode 100644 index 000000000..0c9ed5ef9 --- /dev/null +++ b/spec/scenario/RedeemUnderlyingEth.scen @@ -0,0 +1,171 @@ +-- Redeem Tests + +Test "Mint then Redeem All" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + CallMintEth Geoff 0.005e18 cETH + -- Check current affairs + Assert Equal (Erc20 cETH TokenBalance Geoff) 10e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 0.005e18 + Invariant Static (CToken cETH ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + Expect Changes (EtherBalance Geoff) +0.005e18 + RedeemUnderlyingEth Geoff 0.005e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) Zero + Assert Equal (CToken cETH UnderlyingBalance Geoff) Zero + +Test "Mint then Redeem Part" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + CallMintEth Geoff 0.005e18 cETH + -- Check current affairs + Assert Equal (Erc20 cETH TokenBalance Geoff) 10e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 0.005e18 + Invariant Static (CToken cETH ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + Expect Changes (EtherBalance Geoff) +0.001e18 + RedeemUnderlyingEth Geoff 0.001e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 8e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 0.004e18 + +Test "Mint then Redeem Too Much" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + CallMintEth Geoff 0.005e18 cETH + AllowFailures + -- Check and hold static + Invariant Static (CToken cETH ExchangeRateStored) + Invariant Remains (Erc20 cETH TokenBalance Geoff) 10e8 + Invariant Static (EtherBalance Geoff) + -- Now redeem after some time + FastForward 2 Blocks + RedeemUnderlyingEth Geoff 0.0055e18 cETH + -- TODO: This should really be REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, but based on + -- the order of subtractions, total supply comes before account supply. + Assert Failure MATH_ERROR REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED "3" -- TODO: This error is wrong + +Test "Mint then Redeem Zero" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + CallMintEth Geoff 0.005e18 cETH + -- Check and hold static + Invariant Static (CToken cETH ExchangeRateStored) + Invariant Remains (Erc20 cETH TokenBalance Geoff) 10e8 + Invariant Static (EtherBalance Geoff) + -- Now redeem after some time + FastForward 2 Blocks + RedeemUnderlyingEth Geoff 0e18 cETH + +Pending "Mint then redeem with interest - no reserves" + Invariant Success + NewComptroller + ListedCToken ZRX cETH initialExchangeRate:1e9 + Invariant Remains (CToken cETH Reserves) Zero + Prep Geoff 50e18 ZRX cETH + Mint Geoff 50e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 500e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 50e18 + Assert Equal (CToken cETH ExchangeRate) 1e9 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cETH 10e18 5e18 interestRate:0.0001 blocks:5000 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- This is due pro-rata to all holders, but we just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cETH TokenBalance Geoff) 500e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 55e18 + Assert Equal (CToken cETH ExchangeRate) 1.1e9 + -- Now redeem all with interest + Redeem Geoff 500e8 cETH + Assert Equal (Erc20 ZRX TokenBalance Geoff) 55e18 + Assert Equal (Erc20 ZRX TokenBalance cETH) 0e18 + Assert Equal (Erc20 cETH TokenBalance Geoff) 0e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 0e18 + Assert Equal (CToken cETH ExchangeRate) 1e9 + +Pending "Mint then redeem part with interest - no reserves" + Invariant Success + NewComptroller + ListedCToken ZRX cETH initialExchangeRate:1e9 + Invariant Remains (CToken cETH Reserves) Zero + Prep Geoff 50e18 ZRX cETH + Mint Geoff 50e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 500e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 50e18 + Assert Equal (CToken cETH ExchangeRate) 1e9 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cETH 10e18 5e18 interestRate:0.0001 blocks:5000 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- This is due pro-rata to all holders, but we just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cETH TokenBalance Geoff) 500e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 55e18 + Assert Equal (CToken cETH ExchangeRate) 1.1e9 + -- Now redeem all with interest + Redeem Geoff 499e8 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 1e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 0.11e18 + Assert Equal (CToken cETH ExchangeRate) 1.1e9 + +Pending "Mint then redeem with reserves and interest" + Invariant Success + NewComptroller + ListedCToken ZRX cETH initialExchangeRate:1e9 + Prep Geoff 50e18 ZRX cETH + Mint Geoff 50e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 500e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 50e18 + Assert Equal (CToken cETH ExchangeRate) 1e9 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cETH 10e18 5e18 interestRate:0.0001 blocks:5000 reserveRate:0.2 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- The reserves should get 20% of this, or 1e18, and the rest + -- is due pro-rata to all holders. We just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cETH TokenBalance Geoff) 500e8 + Assert Equal (CToken cETH Reserves) 1e18 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 54e18 + -- 55e18 + 0e18 - 1e18 / 500 + Assert Equal (CToken cETH ExchangeRate) 1.08e9 + -- Now redeem all with interest + Redeem Geoff 500e8 cETH + Assert Equal (Erc20 ZRX TokenBalance Geoff) 54e18 + Assert Equal (Erc20 ZRX TokenBalance cETH) 1e18 + Assert Equal (Erc20 cETH TokenBalance Geoff) 0e8 + Assert Equal (CToken cETH Reserves) 1e18 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 0e18 + Assert Equal (CToken cETH ExchangeRate) 1e9 + +Test "Two users Mint, one redeems" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + CallMintEth Geoff 0.002e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 4e8 + Assert Equal (Erc20 cETH TotalSupply) 4e8 + CallMintEth Torrey 0.004e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 4e8 + Assert Equal (Erc20 cETH TokenBalance Torrey) 8e8 + Assert Equal (Erc20 cETH TotalSupply) 12e8 + RedeemUnderlyingEth Torrey 0.0015e18 cETH + Assert Equal (Erc20 cETH TokenBalance Geoff) 4e8 + Assert Equal (Erc20 cETH TokenBalance Torrey) 5e8 + Assert Equal (Erc20 cETH TotalSupply) 9e8 + +Test "Mint then redeem 1 wei" + NewComptroller + ListedEtherToken cETH initialExchangeRate:0.005e9 + CallMintEth Geoff 0.005e18 cETH + AllowFailures + -- Check current affairs + Assert Equal (Erc20 cETH TokenBalance Geoff) 10e8 + Assert Equal (CToken cETH UnderlyingBalance Geoff) 0.005e18 + Invariant Static (CToken cETH ExchangeRateStored) + Invariant Static (EtherBalance Geoff) + -- Now redeem after some time + FastForward 2 Blocks + RedeemUnderlyingEth Geoff 1 cETH + Assert Revert "revert redeemTokens zero" diff --git a/spec/scenario/RedeemUnderlyingWBTC.scen b/spec/scenario/RedeemUnderlyingWBTC.scen new file mode 100644 index 000000000..02b7c4652 --- /dev/null +++ b/spec/scenario/RedeemUnderlyingWBTC.scen @@ -0,0 +1,183 @@ +-- Redeem Tests + +Test "Mint then Redeem All" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 70e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Check current affairs + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 20e8 + -- Any other good invariants? + Invariant Static (CToken cWBTC ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + RedeemUnderlying Geoff 50e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) Zero + Assert Equal (Erc20 WBTC TokenBalance Geoff) 70e8 + +Test "Mint then Redeem Part" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 70e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Check current affairs + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 20e8 + -- Any other good invariants? + Invariant Static (CToken cWBTC ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + RedeemUnderlying Geoff 25e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 250e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 45e8 + +Test "Mint then Redeem Too Much" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 70e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Check and hold static + Invariant Static (CToken cWBTC ExchangeRateStored) + Invariant Remains (Erc20 cWBTC TokenBalance Geoff) 500e8 + Invariant Remains (Erc20 WBTC TokenBalance Geoff) 20e8 + -- Now redeem after some time + FastForward 2 Blocks + AllowFailures + RedeemUnderlying Geoff 50.1e8 cWBTC + Assert Failure MATH_ERROR REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED "3" + +Test "Mint then Redeem Zero" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 70e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Check current affairs + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 20e8 + -- Any other good invariants? + Invariant Static (CToken cWBTC ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + RedeemUnderlying Geoff 0e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 20e8 + +Test "Mint then redeem with interest - no reserves" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Invariant Remains (CToken cWBTC Reserves) Zero + Prep Geoff 50e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 50e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.1 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest WBTC cWBTC 10e8 5e8 interestRate:0.0001 blocks:5000 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e8 of interest for the protocol + -- This is due pro-rata to all holders, but we just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 55e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.11 + -- Now redeem all with interest + -- Exchange rate is now 55e8 ÷ 50e-1 = 1.1e-1 + -- 500e-1 * 1.1e-1 = 55e8 + RedeemUnderlying Geoff 55e8 cWBTC + Assert Equal (Erc20 WBTC TokenBalance Geoff) 55e8 + Assert Equal (Erc20 WBTC TokenBalance cWBTC) 0e8 + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 0e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 0e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.1 + +Test "Mint then redeem part with interest - no reserves" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Invariant Remains (CToken cWBTC Reserves) Zero + Prep Geoff 50e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 50e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.1 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest WBTC cWBTC 10e8 5e8 interestRate:0.0001 blocks:5000 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e8 of interest for the protocol + -- This is due pro-rata to all holders, but we just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 55e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.11 + -- Now redeem all with interest + -- Exchange rate is now 55e8 ÷ 50e-1 = 1.1e-1 + -- 499e-1 * 1.1e-1 = 54.89e8 + RedeemUnderlying Geoff 54.89e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 1e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 0.11e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.11 + +Test "Mint then redeem with reserves and interest" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 50e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 50e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.1 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest WBTC cWBTC 10e8 5e8 interestRate:0.0001 blocks:5000 reserveRate:0.2 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e8 of interest for the protocol + -- The reserves should get 20% of this, or 1e8, and the rest + -- is due pro-rata to all holders. We just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (CToken cWBTC Reserves) 1e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 54e8 + -- 55e8 + 0e8 - 1e8 / 500 + Assert Equal (CToken cWBTC ExchangeRate) 0.108 + -- Now redeem all with interest + -- Exchange rate is 1.08e-1 + -- 500e8 * 1.08e-1 = 54e8 + RedeemUnderlying Geoff 54e8 cWBTC + Assert Equal (Erc20 WBTC TokenBalance Geoff) 54e8 + Assert Equal (Erc20 WBTC TokenBalance cWBTC) 1e8 + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 0e8 + Assert Equal (CToken cWBTC Reserves) 1e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 0e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.1 + +Test "Two users Mint, one redeems" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff Some WBTC cWBTC + Prep Torrey Some WBTC cWBTC + Mint Geoff 2e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 20e8 + Assert Equal (Erc20 cWBTC TotalSupply) 20e8 + Mint Torrey 2e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 20e8 + Assert Equal (Erc20 cWBTC TokenBalance Torrey) 20e8 + Assert Equal (Erc20 cWBTC TotalSupply) 40e8 + RedeemUnderlying Torrey 1e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 20e8 + Assert Equal (Erc20 cWBTC TokenBalance Torrey) 10e8 + Assert Equal (Erc20 cWBTC TotalSupply) 30e8 + +Test "Mint then Redeem 1 wei of underlying is allowed for 1:1 assets" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 70e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Check current affairs + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 20e8 + -- Any other good invariants? + Invariant Static (CToken cWBTC ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + RedeemUnderlying Geoff 1 cWBTC + -- After affairs + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 49999999990 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 2000000001 diff --git a/spec/scenario/RedeemWBTC.scen b/spec/scenario/RedeemWBTC.scen new file mode 100644 index 000000000..e6c415b90 --- /dev/null +++ b/spec/scenario/RedeemWBTC.scen @@ -0,0 +1,226 @@ +-- Redeem Tests + +Test "Mint WBTC then Redeem All" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 70e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Check current affairs + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 20e8 + -- Any other good invariants? + Invariant Static (CToken cWBTC ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + Redeem Geoff 500e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) Zero + Assert Equal (Erc20 WBTC TokenBalance Geoff) 70e8 + +Test "Mint WBTC, Enter and then Redeem All" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 70e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Check current affairs + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 20e8 + -- Any other good invariants? + Invariant Static (CToken cWBTC ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + EnterMarkets Geoff cWBTC + Redeem Geoff 500e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) Zero + Assert Equal (Erc20 WBTC TokenBalance Geoff) 70e8 + +Test "Mint WBTC then Redeem Part" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 70e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Check current affairs + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 20e8 + -- Any other good invariants? + Invariant Static (CToken cWBTC ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + Redeem Geoff 250e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 250e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 45e8 + +Test "Mint WBTC then Redeem Too Much" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 70e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Check and hold static + Invariant Static (CToken cWBTC ExchangeRateStored) + Invariant Remains (Erc20 cWBTC TokenBalance Geoff) 500e8 + Invariant Remains (Erc20 WBTC TokenBalance Geoff) 20e8 + -- Now redeem after some time + FastForward 2 Blocks + AllowFailures + Redeem Geoff 501e8 cWBTC + Assert Failure MATH_ERROR REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED "3" + +Test "Mint WBTC then Redeem Zero" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 70e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Check current affairs + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 20e8 + -- Any other good invariants? + Invariant Static (CToken cWBTC ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + Redeem Geoff 0e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 20e8 + +Test "Mint WBTC then redeem with interest - no reserves" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Invariant Remains (CToken cWBTC Reserves) Zero + Prep Geoff 50e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 50e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.1 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest WBTC cWBTC 10e8 5e8 interestRate:0.0001 blocks:5000 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e8 of interest for the protocol + -- This is due pro-rata to all holders, but we just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 55e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.11 + -- Now redeem all with interest + Redeem Geoff 500e8 cWBTC + Assert Equal (Erc20 WBTC TokenBalance Geoff) 55e8 + Assert Equal (Erc20 WBTC TokenBalance cWBTC) 0e8 + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 0e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 0e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.1 + +Test "Mint WBTC then redeem part with interest - no reserves" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Invariant Remains (CToken cWBTC Reserves) Zero + Prep Geoff 50e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 50e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.1 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest WBTC cWBTC 10e8 5e8 interestRate:0.0001 blocks:5000 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e8 of interest for the protocol + -- This is due pro-rata to all holders, but we just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 55e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.11 + -- Now redeem all with interest + Redeem Geoff 499e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 1e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 0.11e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.11 + +Test "Mint WBTC then redeem with reserves and interest" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 50e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 50e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.1 + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest WBTC cWBTC 10e8 5e8 interestRate:0.0001 blocks:5000 reserveRate:0.2 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e8 of interest for the protocol + -- The reserves should get 20% of this, or 1e8, and the rest + -- is due pro-rata to all holders. We just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 500e8 + Assert Equal (CToken cWBTC Reserves) 1e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 54e8 + -- 55e8 + 0e8 - 1e8 / 500 + Assert Equal (CToken cWBTC ExchangeRate) 0.108 + -- Now redeem all with interest + Redeem Geoff 500e8 cWBTC + Assert Equal (Erc20 WBTC TokenBalance Geoff) 54e8 + Assert Equal (Erc20 WBTC TokenBalance cWBTC) 1e8 + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 0e8 + Assert Equal (CToken cWBTC Reserves) 1e8 + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) 0e8 + Assert Equal (CToken cWBTC ExchangeRate) 0.1 + +Test "Two users Mint WBTC, one redeems" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff Some WBTC cWBTC + Prep Torrey Some WBTC cWBTC + Mint Geoff 2e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 20e8 + Assert Equal (Erc20 cWBTC TotalSupply) 20e8 + Mint Torrey 2e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 20e8 + Assert Equal (Erc20 cWBTC TokenBalance Torrey) 20e8 + Assert Equal (Erc20 cWBTC TotalSupply) 40e8 + Redeem Torrey 10e8 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) 20e8 + Assert Equal (Erc20 cWBTC TokenBalance Torrey) 10e8 + Assert Equal (Erc20 cWBTC TotalSupply) 30e8 + +Test "Redeem WBTC transfer out fails" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 70e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Check current affairs + Invariant Remains (Erc20 cWBTC TokenBalance Geoff) 500e8 + Invariant Remains (Erc20 WBTC TokenBalance Geoff) 20e8 + Invariant Static (CToken cWBTC ExchangeRateStored) + -- Now redeem after some time + FastForward 2 Blocks + Erc20 WBTC Pause + AllowFailures + Redeem Geoff 500e8 cWBTC + Assert Revert + +Test "Mint WBTC, Enter, then Redeem Too Much (collateral factor: 0)" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff 70e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Check and hold static + Invariant Static (CToken cWBTC ExchangeRateStored) + Invariant Remains (Erc20 cWBTC TokenBalance Geoff) 500e8 + Invariant Remains (Erc20 WBTC TokenBalance Geoff) 20e8 + -- Now redeem after some time + FastForward 2 Blocks + EnterMarkets Geoff cWBTC + AllowFailures + Redeem Geoff 501e8 cWBTC + Assert Failure MATH_ERROR REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED "3" + +Test "Mint WBTC, Enter, then Redeem Too Much (collateral factor: 0.1)" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Comptroller SetCollateralFactor cWBTC 0.1 + Prep Geoff 70e8 WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Check and hold static + Invariant Static (CToken cWBTC ExchangeRateStored) + Invariant Remains (Erc20 cWBTC TokenBalance Geoff) 500e8 + Invariant Remains (Erc20 WBTC TokenBalance Geoff) 20e8 + -- Now redeem after some time + FastForward 2 Blocks + EnterMarkets Geoff cWBTC + AllowFailures + Redeem Geoff 501e8 cWBTC + Assert Failure COMPTROLLER_REJECTION REDEEM_COMPTROLLER_REJECTION INSUFFICIENT_LIQUIDITY diff --git a/spec/scenario/ReduceReserves.scen b/spec/scenario/ReduceReserves.scen new file mode 100644 index 000000000..670cdba6d --- /dev/null +++ b/spec/scenario/ReduceReserves.scen @@ -0,0 +1,136 @@ + +Test "Reduce all reserves and verify effects" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 50e18 ZRX cZRX + Mint Geoff 50e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 500e8) + Assert Equal (CToken cZRX UnderlyingBalance Geoff) (Exactly 50e18) + Assert Equal (CToken cZRX ExchangeRate) (Exactly 1e9) + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cZRX 10e18 5e18 interestRate:0.0001 blocks:5000 reserveRate:0.2 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- The reserves should get 20% of this, or 1e18, and the rest + -- is due pro-rata to all holders. We just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 ZRX TokenBalance cZRX) (Exactly 55e18) + Assert Equal (Erc20 ZRX TokenBalance Root) (Exactly 0e18) + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 500e8) + Assert Equal (CToken cZRX Reserves) (Exactly 1e18) + Assert Equal (CToken cZRX UnderlyingBalance Geoff) (Exactly 54e18) + -- (55.0e18+0.0e18-1.0e18)/500.0e8 + Assert Equal (CToken cZRX ExchangeRate) (Exactly 1.08e9) + -- Now, let's pull out all of our reserves (1e18) + ReduceReserves 1e18 cZRX + Assert Equal (Erc20 ZRX TokenBalance cZRX) (Exactly 54e18) + Assert Equal (Erc20 ZRX TokenBalance Root) (Exactly 1e18) + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 500e8) + Assert Equal (CToken cZRX Reserves) (Exactly 0e18) + Assert Equal (CToken cZRX UnderlyingBalance Geoff) (Exactly 54e18) + -- (54.0e18+0.0e18-0.0e18)/500.0e8 + Assert Equal (CToken cZRX ExchangeRate) (Exactly 1.08e9) + +Test "Reduce partial reserves and verify effects" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 50e18 ZRX cZRX + Mint Geoff 50e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 500e8) + Assert Equal (CToken cZRX UnderlyingBalance Geoff) (Exactly 50e18) + Assert Equal (CToken cZRX ExchangeRate) (Exactly 1e9) + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cZRX 10e18 5e18 interestRate:0.0001 blocks:5000 reserveRate:0.2 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- The reserves should get 20% of this, or 1e18, and the rest + -- is due pro-rata to all holders. We just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 ZRX TokenBalance cZRX) (Exactly 55e18) + Assert Equal (Erc20 ZRX TokenBalance Root) (Exactly 0e18) + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 500e8) + Assert Equal (CToken cZRX Reserves) (Exactly 1e18) + Assert Equal (CToken cZRX UnderlyingBalance Geoff) (Exactly 54e18) + -- (55.0e18+0.0e18-1.0e18)/500.0e8 + Assert Equal (CToken cZRX ExchangeRate) (Exactly 1.08e9) + -- Now, let's pull out all of our reserves (1e18) + ReduceReserves 0.5e18 cZRX + Assert Equal (Erc20 ZRX TokenBalance cZRX) (Exactly 54.5e18) + Assert Equal (Erc20 ZRX TokenBalance Root) (Exactly 0.5e18) + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 500e8) + Assert Equal (CToken cZRX Reserves) (Exactly 0.5e18) + Assert Equal (CToken cZRX UnderlyingBalance Geoff) (Exactly 54e18) + -- (54.5e18+0.5e18-0.0e18)/500.0e8 + Assert Equal (CToken cZRX ExchangeRate) (Exactly 1.08e9) + +Test "Redeem all and then reduce all reserves" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff 50e18 ZRX cZRX + Mint Geoff 50e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 500e8) + Assert Equal (CToken cZRX UnderlyingBalance Geoff) (Exactly 50e18) + Assert Equal (CToken cZRX ExchangeRate) (Exactly 1e9) + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest ZRX cZRX 10e18 5e18 interestRate:0.0001 blocks:5000 reserveRate:0.2 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- The reserves should get 20% of this, or 1e18, and the rest + -- is due pro-rata to all holders. We just have one, so + -- let's check that account is given correct new balance. + Assert Equal (Erc20 ZRX TokenBalance cZRX) (Exactly 55e18) + Assert Equal (Erc20 ZRX TokenBalance Root) (Exactly 0e18) + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 500e8) + Assert Equal (CToken cZRX Reserves) (Exactly 1e18) + Assert Equal (CToken cZRX UnderlyingBalance Geoff) (Exactly 54e18) + -- (55.0e18+0.0e18-1.0e18)/500.0e8 + Assert Equal (CToken cZRX ExchangeRate) (Exactly 1.08e9) + -- Now let's redeem all + Redeem Geoff 500e8 cZRX + -- Check our values + Assert Equal (Erc20 ZRX TokenBalance Geoff) (Exactly 54e18) + Assert Equal (Erc20 ZRX TokenBalance cZRX) (Exactly 1e18) + Assert Equal (Erc20 ZRX TokenBalance Root) (Exactly 0e18) + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 0e8) + Assert Equal (CToken cZRX Reserves) (Exactly 1e18) + Assert Equal (CToken cZRX UnderlyingBalance Geoff) (Exactly 0e18) + -- 0 tokens implies initial exchange rate + Assert Equal (CToken cZRX ExchangeRate) (Exactly 1e9) + -- Then now, let's pull out all of our reserves (1e18) + ReduceReserves 1e18 cZRX + Assert Equal (Erc20 ZRX TokenBalance Geoff) (Exactly 54e18) + Assert Equal (Erc20 ZRX TokenBalance cZRX) (Exactly 0e18) + Assert Equal (Erc20 ZRX TokenBalance Root) (Exactly 1e18) + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 0e8) + Assert Equal (CToken cZRX Reserves) (Exactly 0e18) + Assert Equal (CToken cZRX UnderlyingBalance Geoff) (Exactly 0e18) + -- 0 tokens implies initial exchange rate + Assert Equal (CToken cZRX ExchangeRate) (Exactly 1e9) + +Test "Reduce reserves WBTC when paused" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:1e9 tokenType:WBTC + Prep Geoff 50e18 WBTC cWBTC + Mint Geoff 50e18 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) (Exactly 500e8) + Assert Equal (CToken cWBTC UnderlyingBalance Geoff) (Exactly 50e18) + Assert Equal (CToken cWBTC ExchangeRate) (Exactly 1e9) + -- Get some brah to borrow then repay + BorrowAndRepayWithInterest WBTC cWBTC 10e18 5e18 interestRate:0.0001 blocks:5000 reserveRate:0.2 + -- We've accrued 10% interest for 5 blocks, or 50% of the amount, + -- thus, we should have accrued 5e18 of interest for the protocol + -- The reserves should get 20% of this, or 1e18, and the rest + -- is due pro-rata to all holders. We just have one, so + -- let's check that account is given correct new balance. + Invariant Remains (Erc20 WBTC TokenBalance cWBTC) (Exactly 55e18) + Invariant Remains (Erc20 WBTC TokenBalance Root) (Exactly 0e18) + Invariant Remains (Erc20 cWBTC TokenBalance Geoff) (Exactly 500e8) + Invariant Remains (CToken cWBTC Reserves) (Exactly 1e18) + Invariant Remains (CToken cWBTC UnderlyingBalance Geoff) (Exactly 54e18) + -- (55.0e18+0.0e18-1.0e18)/500.0e8 + Invariant Remains (CToken cWBTC ExchangeRate) (Exactly 1.08e9) + -- Now, let's pull out all of our reserves (1e18) + Erc20 WBTC Pause + AllowFailures + ReduceReserves 1e18 cWBTC + Assert Revert diff --git a/spec/scenario/RepayBorrow.scen b/spec/scenario/RepayBorrow.scen new file mode 100644 index 000000000..c90ecb35b --- /dev/null +++ b/spec/scenario/RepayBorrow.scen @@ -0,0 +1,173 @@ +-- Tests for repaying borrows + +Macro NewBorrow borrowAmount borrowRate + NewComptroller price:1.0 -- TODO: This should really be a price for a specific asset + NewCToken ZRX cZRX + NewCToken BAT cBAT borrowRate -- note: cannot use macros with named args right now + Give cBAT 10e18 BAT -- Faucet some bat to borrow + Support cZRX collateralFactor:0.5 + Support cBAT collateralFactor:0.5 + Prep Geoff Some ZRX cZRX + Mint Geoff 100e18 cZRX + EnterMarkets Geoff cZRX cBAT + Borrow Geoff borrowAmount cBAT + +Test "Borrow, hold a few blocks, and repay part" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 1e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cBAT BorrowBalance Geoff) 2.5e18 + -- Now let's repay one full token + From Geoff (Erc20 BAT Approve cBAT 1.0e18) + RepayBorrow Geoff 1.0e18 cBAT + Assert Equal (CToken cBAT BorrowBalance Geoff) 1.5e18 + -- Let's check the overall numbers + Assert Equal (Erc20 BAT TokenBalance Geoff) Zero + Assert Equal (Erc20 BAT TokenBalance cBAT) 10e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 1.5e18 + FastForward 2000 Blocks -- 1.5e18 * (1 + 2000 * 0.0005) + Assert Equal (CToken cBAT BorrowBalance Geoff) 3e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 3e18 + +Test "Borrow, hold a few blocks, and repay full" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 1e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cBAT BorrowBalance Geoff) 2.5e18 + -- Now let's repay fully + Give Geoff 1.5e18 BAT -- Geoff had the 1.0e18 borrowed BAT + From Geoff (Erc20 BAT Approve cBAT 2.5e18) + RepayBorrow Geoff 2.5e18 cBAT + Assert Equal (CToken cBAT BorrowBalance Geoff) 0e18 + -- Let's check the overall numbers + Assert Equal (Erc20 BAT TokenBalance Geoff) 0e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 11.5e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 0e18 + FastForward 2000 Blocks -- 0e18 * (1 + 2000 * 0.0005) + Assert Equal (CToken cBAT BorrowBalance Geoff) 0e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 0e18 + +Test "Borrow, hold a few blocks, and repay too much" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 1e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cBAT BorrowBalance Geoff) 2.5e18 + -- Now let's repay fully + AllowFailures + Prep Geoff 10e18 BAT cBAT + Expect Changes (Erc20 BAT TokenBalance Geoff) Zero + Expect Changes (Erc20 BAT TokenBalance cBAT) Zero + RepayBorrow Geoff 10e18 cBAT + Assert Failure MATH_ERROR REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED "3" + -- Let's check the overall numbers + Assert Equal (CToken cBAT BorrowBalance Geoff) 2.5e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 2.5e18 + +Test "Borrow, and get a negative total cash situation" + Invariant Success + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Let's zoom way forward into the future + FastForward 98000 Blocks -- 1e18 * (1 + 98000 * 0.0005) + Assert Equal (CToken cBAT BorrowBalance Geoff) 50e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 50e18 + -- Now let's repay one full token + From Geoff (Erc20 BAT Approve cBAT 1.0e18) + RepayBorrow Geoff 1.0e18 cBAT + Assert Equal (CToken cBAT BorrowBalance Geoff) 49e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 49e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 0e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 10e18 + +Test "Borrow, hold a few blocks, and repay behalf part" + Invariant Success + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 1e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 9e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 1e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cBAT BorrowBalance Geoff) 2.5e18 + -- Now let's repay one full token from another user + Prep Torrey 1.0e18 BAT cBAT + RepayBorrowBehalf Torrey Geoff 1.0e18 cBAT + Assert Equal (CToken cBAT BorrowBalance Torrey) Zero + Assert Equal (CToken cBAT BorrowBalance Geoff) 1.5e18 + -- Let's check the overall numbers + Assert Equal (Erc20 BAT TokenBalance Torrey) 0e18 + Assert Equal (Erc20 BAT TokenBalance Geoff) 1e18 + Assert Equal (Erc20 BAT TokenBalance cBAT) 10e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 1.5e18 + FastForward 2000 Blocks -- 1.5e18 * (1 + 2000 * 0.0005) + Assert Equal (CToken cBAT BorrowBalance Torrey) Zero + Assert Equal (CToken cBAT BorrowBalance Geoff) 3e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 3e18 + +Test "Prohibit repay by comptroller rejection due to mock unlist" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 1e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cBAT BorrowBalance Geoff) 2.5e18 + -- Now let's repay fully + AllowFailures + Prep Geoff 10e18 BAT cBAT + Expect Changes (Erc20 BAT TokenBalance Geoff) Zero + Expect Changes (Erc20 BAT TokenBalance cBAT) Zero + Comptroller UnList cZRX -- Mock unlist ZRX + RepayBorrow Geoff 2.5e18 cZRX + Assert Failure COMPTROLLER_REJECTION REPAY_BORROW_COMPTROLLER_REJECTION MARKET_NOT_LISTED + -- Let's check the overall numbers + Assert Equal (CToken cBAT BorrowBalance Geoff) 2.5e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 2.5e18 + +Test "Repay fails with insufficient allowance" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 1e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cBAT BorrowBalance Geoff) 2.5e18 + -- Now let's repay fully + AllowFailures + Prep Geoff 100e18 BAT cBAT allowanceAmount:1.5e18 + Expect Changes (Erc20 BAT TokenBalance Geoff) Zero + Expect Changes (Erc20 BAT TokenBalance cBAT) Zero + RepayBorrow Geoff 2.5e18 cBAT + Assert Failure TOKEN_INSUFFICIENT_ALLOWANCE REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE + -- Let's check the overall numbers + Assert Equal (CToken cBAT BorrowBalance Geoff) 2.5e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 2.5e18 + +Test "Repay fails with insufficient balance" + NewBorrow borrowAmount:1e18 borrowRate:0.0005 + Assert Equal (CToken cBAT BorrowBalance Geoff) 1e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 1e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cBAT BorrowBalance Geoff) 2.5e18 + -- Now let's repay fully + AllowFailures + Prep Geoff 0e18 BAT cBAT allowanceAmount:2.5e18 + Expect Changes (Erc20 BAT TokenBalance Geoff) Zero + Expect Changes (Erc20 BAT TokenBalance cBAT) Zero + RepayBorrow Geoff 2.5e18 cBAT + Assert Failure TOKEN_INSUFFICIENT_BALANCE REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE + -- Let's check the overall numbers + Assert Equal (CToken cBAT BorrowBalance Geoff) 2.5e18 + Assert Equal (CToken cBAT TotalBorrowsCurrent) 2.5e18 diff --git a/spec/scenario/RepayBorrowEth.scen b/spec/scenario/RepayBorrowEth.scen new file mode 100644 index 000000000..767466af2 --- /dev/null +++ b/spec/scenario/RepayBorrowEth.scen @@ -0,0 +1,206 @@ +-- Tests for repaying borrows + +Macro SetupBorrow borrowRate + NewComptroller price:1.0 -- TODO: This should really be a price for a specific asset + ListedCToken ZRX cZRX borrowRate + ListedEtherToken cETH borrowRate 0.005e9 + SetCollateralFactor cZRX collateralFactor:0.5 + SetCollateralFactor cETH collateralFactor:0.5 + Donate cETH 0.003e18 + Prep Geoff Some ZRX cZRX + Mint Geoff 100e18 cZRX + EnterMarkets Geoff cZRX cETH + +Macro NewBorrowEth borrowAmount borrowRate + SetupBorrow borrowRate + Borrow Geoff borrowAmount cETH + +Test "Borrow, hold a few blocks, and repay part" + NewBorrowEth borrowAmount:0.001e18 borrowRate:0.0005 + Assert Equal (CToken cETH BorrowBalance Geoff) 0.001e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.001e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) 0.0025e18 + -- Now let's repay one full token + Expect Changes (EtherBalance Geoff) -0.001e18 + Expect Changes (EtherBalance cETH) +0.001e18 + RepayBorrowEth Geoff 0.001e18 cETH + ---- Let's check the overall numbers + Assert Equal (CToken cETH BorrowBalance Geoff) 0.0015e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.0015e18 + FastForward 2000 Blocks -- 0.0015e18 * (1 + 2000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) 0.003e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.003e18 + +Test "Borrow, hold a few blocks, and repay part via maximillion" + NewBorrowEth borrowAmount:0.001e18 borrowRate:0.0005 + Maximillion Deploy cETH + Assert Equal (CToken cETH BorrowBalance Geoff) 0.001e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.001e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) 0.0025e18 + -- Now let's repay one full token + Expect Changes (EtherBalance Geoff) -0.001e18 + Expect Changes (EtherBalance cETH) +0.001e18 + RepayBorrowEthMax Geoff 0.001e18 cETH + ---- Let's check the overall numbers + Assert Equal (CToken cETH BorrowBalance Geoff) 0.0015e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.0015e18 + FastForward 2000 Blocks -- 0.0015e18 * (1 + 2000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) 0.003e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.003e18 + +Test "Don't borrow and then do repay" + SetupBorrow borrowRate:0.0005 + Assert Equal (CToken cETH BorrowBalance Geoff) Zero + Assert Equal (CToken cETH TotalBorrowsCurrent) Zero + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0 * (1 + 3000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) Zero + -- Now let's repay one full token + Expect Changes (EtherBalance Geoff) Zero + Expect Changes (EtherBalance cETH) Zero + RepayBorrowEth Geoff 0 cETH + ---- Let's check the overall numbers + Assert Equal (CToken cETH BorrowBalance Geoff) Zero + Assert Equal (CToken cETH TotalBorrowsCurrent) Zero + +Test "Don't borrow and repay part via maximillion" + SetupBorrow borrowRate:0.0005 + Maximillion Deploy cETH + Assert Equal (CToken cETH BorrowBalance Geoff) Zero + Assert Equal (CToken cETH TotalBorrowsCurrent) Zero + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0 * (1 + 3000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) Zero + -- Now let's repay one full token + Expect Changes (EtherBalance Geoff) Zero + Expect Changes (EtherBalance cETH) Zero + RepayBorrowEthMax Geoff 0.001e18 cETH + ---- Let's check the overall numbers + Assert Equal (CToken cETH BorrowBalance Geoff) Zero + Assert Equal (CToken cETH TotalBorrowsCurrent) Zero + +Test "Borrow, hold a few blocks, and repay full" + NewBorrowEth borrowAmount:0.001e18 borrowRate:0.0005 + Assert Equal (CToken cETH BorrowBalance Geoff) 0.001e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.001e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) 0.0025e18 + -- Now let's repay fully + Expect Changes (EtherBalance Geoff) -0.0025e18 + Expect Changes (EtherBalance cETH) +0.0025e18 + RepayBorrowEth Geoff 0.0025e18 cETH + -- Let's check the overall numbers + Assert Equal (CToken cETH BorrowBalance Geoff) Zero + Assert Equal (CToken cETH TotalBorrowsCurrent) Zero + FastForward 2000 Blocks -- 0e18 * (1 + 2000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) Zero + Assert Equal (CToken cETH TotalBorrowsCurrent) Zero + +Test "Borrow, hold a few blocks, and repay full via maximillion" + NewBorrowEth borrowAmount:0.001e18 borrowRate:0.0005 + Maximillion Deploy cETH + Assert Equal (CToken cETH BorrowBalance Geoff) 0.001e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.001e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) 0.0025e18 + -- Now let's repay fully + Expect Changes (EtherBalance Geoff) -0.0025e18 + Expect Changes (EtherBalance cETH) +0.0025e18 + RepayBorrowEthMax Geoff 0.0025e18 cETH + -- Let's check the overall numbers + Assert Equal (CToken cETH BorrowBalance Geoff) Zero + Assert Equal (CToken cETH TotalBorrowsCurrent) Zero + FastForward 2000 Blocks -- 0e18 * (1 + 2000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) Zero + Assert Equal (CToken cETH TotalBorrowsCurrent) Zero + +Test "Borrow, hold a few blocks, and repay too much" + NewBorrowEth borrowAmount:0.001e18 borrowRate:0.0005 + Assert Equal (CToken cETH BorrowBalance Geoff) 0.001e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.001e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) 0.0025e18 + -- Now let's repay fully + Expect Changes (EtherBalance Geoff) Zero + Expect Changes (EtherBalance cETH) Zero + -- TODO: This currently drains the sent-eth + AllowFailures + RepayBorrowEth Geoff 1.0e18 cETH + Assert Revert "revert repayBorrow failed" + -- Let's check the overall numbers + Assert Equal (CToken cETH BorrowBalance Geoff) 0.0025e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.0025e18 + +Test "Borrow, hold a few blocks, and repay too much via maximillion" + NewBorrowEth borrowAmount:0.001e18 borrowRate:0.0005 + Maximillion Deploy cETH + Assert Equal (CToken cETH BorrowBalance Geoff) 0.001e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.001e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) 0.0025e18 + -- Now let's repay fully + Expect Changes (EtherBalance Geoff) -0.0025e18 + Expect Changes (EtherBalance cETH) +0.0025e18 + RepayBorrowEthMax Geoff 1.0e18 cETH + -- Let's check the overall numbers + Assert Equal (CToken cETH BorrowBalance Geoff) Zero + Assert Equal (CToken cETH TotalBorrowsCurrent) Zero + FastForward 2000 Blocks -- 0e18 * (1 + 2000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) Zero + Assert Equal (CToken cETH TotalBorrowsCurrent) Zero + +Test "Borrow, and get a negative total cash situation" + NewBorrowEth borrowAmount:0.001e18 borrowRate:0.0005 + Assert Equal (CToken cETH BorrowBalance Geoff) 0.001e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.001e18 + -- Let's zoom way forward into the future + FastForward 98000 Blocks -- 0.001e18 * (1 + 98000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) 0.05e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.05e18 + -- Now let's repay one bit + RepayBorrowEth Geoff 0.001e18 cETH + Assert Equal (CToken cETH BorrowBalance Geoff) 0.049e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.049e18 + +Test "Borrow, hold a few blocks, and repay behalf part" + NewBorrowEth borrowAmount:0.001e18 borrowRate:0.0005 + Assert Equal (CToken cETH BorrowBalance Geoff) 0.001e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.001e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) 0.0025e18 + -- Now let's repay one full token from another user + RepayBorrowEthBehalf Torrey Geoff 0.001e18 cETH + Assert Equal (CToken cETH BorrowBalance Torrey) Zero + Assert Equal (CToken cETH BorrowBalance Geoff) 0.0015e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.0015e18 + FastForward 2000 Blocks -- 0.0015e18 * (1 + 2000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Torrey) Zero + Assert Equal (CToken cETH BorrowBalance Geoff) 0.003e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.003e18 + +Test "Prohibit repay by comptroller hook" + NewBorrowEth borrowAmount:0.001e18 borrowRate:0.0005 + Assert Equal (CToken cETH BorrowBalance Geoff) 0.001e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.001e18 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cETH BorrowBalance Geoff) 0.0025e18 + -- Now let's repay one full token + Expect Changes (EtherBalance Geoff) Zero + Expect Changes (EtherBalance cETH) Zero + Comptroller UnList cETH -- Mock unlist cETH + AllowFailures + RepayBorrowEth Geoff 0.001e18 cETH + Assert RevertFailure COMPTROLLER_REJECTION "revert repayBorrow failed" + ---- Let's check the overall numbers + Assert Equal (CToken cETH BorrowBalance Geoff) 0.0025e18 + Assert Equal (CToken cETH TotalBorrowsCurrent) 0.0025e18 diff --git a/spec/scenario/RepayBorrowWBTC.scen b/spec/scenario/RepayBorrowWBTC.scen new file mode 100644 index 000000000..b9381c12d --- /dev/null +++ b/spec/scenario/RepayBorrowWBTC.scen @@ -0,0 +1,189 @@ +-- Tests for repaying borrows + +Macro NewBorrow borrowAmount borrowRate + NewComptroller price:1.0 -- TODO: This should really be a price for a specific asset + NewCToken ZRX cZRX + NewCToken WBTC cWBTC borrowRate 0.1 8 WBTC -- note: cannot use macros with named args right now + Give cWBTC 10e8 WBTC -- Faucet some WBTC to borrow + Support cZRX collateralFactor:0.5 + Support cWBTC collateralFactor:0.5 + Prep Geoff Some ZRX cZRX + Mint Geoff 100e18 cZRX + EnterMarkets Geoff cZRX cWBTC + Borrow Geoff borrowAmount cWBTC + +Test "Borrow WBTC, hold a few blocks, and repay part" + NewBorrow borrowAmount:1e8 borrowRate:0.0005 + Assert Equal (CToken cWBTC BorrowBalance Geoff) 1e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 1e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 1e8 + Assert Equal (Erc20 WBTC TokenBalance cWBTC) 9e8 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 1e18 * (1 + 3000 * 0.0005) + Assert Equal (CToken cWBTC BorrowBalance Geoff) 2.5e8 + -- Now let's repay one full token + From Geoff (Erc20 WBTC Approve cWBTC 1.0e8) + RepayBorrow Geoff 1e8 cWBTC + Assert Equal (CToken cWBTC BorrowBalance Geoff) 1.5e8 + -- Let's check the overall numbers + Assert Equal (Erc20 WBTC TokenBalance Geoff) Zero + Assert Equal (Erc20 WBTC TokenBalance cWBTC) 10e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 1.5e8 + FastForward 2000 Blocks -- 1.5e8 * (1 + 2000 * 0.0005) + Assert Equal (CToken cWBTC BorrowBalance Geoff) 3e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 3e8 + +Test "Borrow, hold a few blocks, and repay full" + NewBorrow borrowAmount:1e8 borrowRate:0.0005 + Assert Equal (CToken cWBTC BorrowBalance Geoff) 1e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 1e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 1e8 + Assert Equal (Erc20 WBTC TokenBalance cWBTC) 9e8 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 1e8 * (1 + 3000 * 0.0005) + Assert Equal (CToken cWBTC BorrowBalance Geoff) 2.5e8 + -- Now let's repay fully + Give Geoff 1.5e8 WBTC -- Geoff had the 1.0e8 borrowed WBTC + From Geoff (Erc20 WBTC Approve cWBTC 2.5e8) + RepayBorrow Geoff 2.5e8 cWBTC + Assert Equal (CToken cWBTC BorrowBalance Geoff) 0e8 + -- Let's check the overall numbers + Assert Equal (Erc20 WBTC TokenBalance Geoff) 0e8 + Assert Equal (Erc20 WBTC TokenBalance cWBTC) 11.5e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 0e8 + FastForward 2000 Blocks -- 0e8 * (1 + 2000 * 0.0005) + Assert Equal (CToken cWBTC BorrowBalance Geoff) 0e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 0e8 + +Test "Borrow, hold a few blocks, and repay too much" + NewBorrow borrowAmount:1e8 borrowRate:0.0005 + Assert Equal (CToken cWBTC BorrowBalance Geoff) 1e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 1e8 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e8 * (1 + 3000 * 0.0005) + Assert Equal (CToken cWBTC BorrowBalance Geoff) 2.5e8 + -- Now let's repay fully + AllowFailures + Prep Geoff 10e8 WBTC cWBTC + Expect Changes (Erc20 WBTC TokenBalance Geoff) Zero + Expect Changes (Erc20 WBTC TokenBalance cWBTC) Zero + RepayBorrow Geoff 10e8 cWBTC + Assert Failure MATH_ERROR REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED "3" + -- Let's check the overall numbers + Assert Equal (CToken cWBTC BorrowBalance Geoff) 2.5e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 2.5e8 + +Test "Borrow, and get a negative total cash situation" + Invariant Success + NewBorrow borrowAmount:1e8 borrowRate:0.0005 + Assert Equal (CToken cWBTC BorrowBalance Geoff) 1e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 1e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 1e8 + Assert Equal (Erc20 WBTC TokenBalance cWBTC) 9e8 + -- Let's zoom way forward into the future + FastForward 98000 Blocks -- 1e8 * (1 + 98000 * 0.0005) + Assert Equal (CToken cWBTC BorrowBalance Geoff) 50e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 50e8 + -- Now let's repay one full token + From Geoff (Erc20 WBTC Approve cWBTC 1.0e8) + RepayBorrow Geoff 1.0e8 cWBTC + Assert Equal (CToken cWBTC BorrowBalance Geoff) 49e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 49e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 0e8 + Assert Equal (Erc20 WBTC TokenBalance cWBTC) 10e8 + +Test "Borrow, hold a few blocks, and repay behalf part" + Invariant Success + NewBorrow borrowAmount:1e8 borrowRate:0.0005 + Assert Equal (CToken cWBTC BorrowBalance Geoff) 1e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 1e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 1e8 + Assert Equal (Erc20 WBTC TokenBalance cWBTC) 9e8 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 1e8 * (1 + 3000 * 0.0005) + Assert Equal (CToken cWBTC BorrowBalance Geoff) 2.5e8 + -- Now let's repay one full token from another user + Prep Torrey 1.0e8 WBTC cWBTC + RepayBorrowBehalf Torrey Geoff 1.0e8 cWBTC + Assert Equal (CToken cWBTC BorrowBalance Torrey) Zero + Assert Equal (CToken cWBTC BorrowBalance Geoff) 1.5e8 + -- Let's check the overall numbers + Assert Equal (Erc20 WBTC TokenBalance Torrey) 0e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 1e8 + Assert Equal (Erc20 WBTC TokenBalance cWBTC) 10e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 1.5e8 + FastForward 2000 Blocks -- 1.5e8 * (1 + 2000 * 0.0005) + Assert Equal (CToken cWBTC BorrowBalance Torrey) Zero + Assert Equal (CToken cWBTC BorrowBalance Geoff) 3e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 3e8 + +Test "Prohibit repay by comptroller rejection due to mock unlist" + NewBorrow borrowAmount:1e8 borrowRate:0.0005 + Assert Equal (CToken cWBTC BorrowBalance Geoff) 1e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 1e8 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e8 * (1 + 3000 * 0.0005) + Assert Equal (CToken cWBTC BorrowBalance Geoff) 2.5e8 + -- Now let's repay fully + AllowFailures + Prep Geoff 10e8 WBTC cWBTC + Expect Changes (Erc20 WBTC TokenBalance Geoff) Zero + Expect Changes (Erc20 WBTC TokenBalance cWBTC) Zero + Comptroller UnList cZRX -- Mock unlist ZRX + RepayBorrow Geoff 2.5e8 cZRX + Assert Failure COMPTROLLER_REJECTION REPAY_BORROW_COMPTROLLER_REJECTION MARKET_NOT_LISTED + -- Let's check the overall numbers + Assert Equal (CToken cWBTC BorrowBalance Geoff) 2.5e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 2.5e8 + +Test "Borrow WBTC, can't repay when paused" + NewBorrow borrowAmount:1e8 borrowRate:0.0005 + Assert Equal (CToken cWBTC BorrowBalance Geoff) 1e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 1e8 + Assert Equal (Erc20 WBTC TokenBalance Geoff) 1e8 + Assert Equal (Erc20 WBTC TokenBalance cWBTC) 9e8 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 1e18 * (1 + 3000 * 0.0005) + Invariant Remains (CToken cWBTC BorrowBalance Geoff) 2.5e8 + -- Now let's repay one full token + From Geoff (Erc20 WBTC Approve cWBTC 1.0e8) + Erc20 WBTC Pause + AllowFailures + RepayBorrow Geoff 1e8 cWBTC + Assert Revert + +Test "Repay fails with insufficient allowance" + NewBorrow borrowAmount:1e8 borrowRate:0.0005 + Assert Equal (CToken cWBTC BorrowBalance Geoff) 1e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 1e8 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e8 * (1 + 3000 * 0.0005) + Assert Equal (CToken cWBTC BorrowBalance Geoff) 2.5e8 + -- Now let's repay fully + AllowFailures + Prep Geoff 100e8 WBTC cWBTC allowanceAmount:1.5e8 + Expect Changes (Erc20 WBTC TokenBalance Geoff) Zero + Expect Changes (Erc20 WBTC TokenBalance cWBTC) Zero + RepayBorrow Geoff 2.5e8 cWBTC + Assert Failure TOKEN_INSUFFICIENT_ALLOWANCE REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE + -- Let's check the overall numbers + Assert Equal (CToken cWBTC BorrowBalance Geoff) 2.5e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 2.5e8 + +Test "Repay fails with insufficient balance" + NewBorrow borrowAmount:1e8 borrowRate:0.0005 + Assert Equal (CToken cWBTC BorrowBalance Geoff) 1e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 1e8 + -- Now let's add some blocks and see what happs + FastForward 3000 Blocks -- 0.001e8 * (1 + 3000 * 0.0005) + Assert Equal (CToken cWBTC BorrowBalance Geoff) 2.5e8 + -- Now let's repay fully + AllowFailures + Prep Geoff 0e8 WBTC cWBTC allowanceAmount:2.5e8 + Expect Changes (Erc20 WBTC TokenBalance Geoff) Zero + Expect Changes (Erc20 WBTC TokenBalance cWBTC) Zero + RepayBorrow Geoff 2.5e8 cWBTC + Assert Failure TOKEN_INSUFFICIENT_BALANCE REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE + -- Let's check the overall numbers + Assert Equal (CToken cWBTC BorrowBalance Geoff) 2.5e8 + Assert Equal (CToken cWBTC TotalBorrowsCurrent) 2.5e8 diff --git a/spec/scenario/Seize.scen b/spec/scenario/Seize.scen new file mode 100644 index 000000000..ac7aa3c87 --- /dev/null +++ b/spec/scenario/Seize.scen @@ -0,0 +1,50 @@ + +Test "Fail to seize calling directly" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + ListedCToken BAT cBAT initialExchangeRate:1e9 + Prep Geoff Some ZRX cZRX + Mint Geoff 50e18 cZRX + Invariant Remains (Erc20 cZRX TokenBalance Geoff) 50e9 + AllowFailures + Seize 1e9 cZRX caller:Geoff liquidator:Geoff borrower:Torrey + -- The caller must be from another cToken market, thus this fails + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_SEIZE_COMPTROLLER_REJECTION MARKET_NOT_LISTED + +Test "Seize tokens with a paused WBTC cToken-- like normal" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff Some ZRX cZRX + Mint Geoff 50e18 cZRX + Erc20 WBTC Pause + Invariant Remains (Erc20 cZRX TokenBalance Geoff) 50e9 + AllowFailures + Seize 1e9 cWBTC caller:Geoff liquidator:Geoff borrower:Torrey + -- The caller must be from another cToken market, thus this fails + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_SEIZE_COMPTROLLER_REJECTION MARKET_NOT_LISTED + +Test "Not able to seize tokens with a malicious unlisted cToken" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + NewCToken EVL cEVL initialExchangeRate:1e9 cTokenType:CEvil + Prep Geoff Some ZRX cZRX + Mint Geoff 50e18 cZRX + Invariant Remains (Erc20 cZRX TokenBalance Geoff) 50e9 + Invariant Static (Erc20 cZRX TokenBalance Geoff) + Invariant Static (Erc20 cZRX TokenBalance Torrey) + AllowFailures + EvilSeize cEVL 1e9 cZRX seizer:Geoff seizee:Torrey + -- The caller must be from another cToken market, thus this fails + Assert Failure COMPTROLLER_REJECTION LIQUIDATE_SEIZE_COMPTROLLER_REJECTION MARKET_NOT_LISTED + +Test "Able to seize tokens with a malicious listed cToken" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + ListedCToken EVL cEVL initialExchangeRate:1e9 cTokenType:CEvil + Prep Geoff Some ZRX cZRX + Mint Geoff 50e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) 50e9 + Expect Changes (Erc20 cZRX TokenBalance Geoff) -1e9 + Expect Changes (Erc20 cZRX TokenBalance Torrey) +1e9 + EvilSeize cEVL 1e9 cZRX seizer:Torrey seizee:Geoff diff --git a/spec/scenario/SetComptroller.scen b/spec/scenario/SetComptroller.scen new file mode 100644 index 000000000..e3a7f89d0 --- /dev/null +++ b/spec/scenario/SetComptroller.scen @@ -0,0 +1,26 @@ +-- Sets for `_setComptroller` Admin Function + +Test "Set Comptroller" + NewComptroller + NewCToken ZRX cZRX + Assert Equal (CToken cZRX Comptroller) (Unitroller Address) + ComptrollerImpl Deploy Scenario NewComptroller + From Root (CToken cZRX SetComptroller (ComptrollerImpl NewComptroller Address)) + -- TODO: Fix log assertion + -- Assert Log "NewComptroller" ("oldComptroller" (Unitroller Address)) ("newComptroller" (ComptrollerImpl NewComptroller Address)) + Assert Equal (CToken cZRX Comptroller) (ComptrollerImpl NewComptroller Address) + +Test "Fail when is not a comptroller" + NewComptroller + NewCToken ZRX cZRX + Invariant Remains (CToken cZRX Comptroller) (Unitroller Address) + AllowFailures + From Root (CToken cZRX SetComptroller (PriceOracle Address)) + Assert Revert + +Test "Fail to set comptroller as not admin" + NewComptroller + NewCToken ZRX cZRX + AllowFailures + From Geoff (CToken cZRX SetComptroller (PriceOracle Address)) + Assert Failure UNAUTHORIZED SET_COMPTROLLER_OWNER_CHECK diff --git a/spec/scenario/Supply.scen.old b/spec/scenario/Supply.scen.old new file mode 100644 index 000000000..5ef9eedee --- /dev/null +++ b/spec/scenario/Supply.scen.old @@ -0,0 +1,59 @@ +-- Supply Tests + +Test "Geoff supplies Ether and we check 2 future balances and then supply again" + AddToken Ether + SupportMarket Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Geoff Ether "10.0e18" + Faucet Geoff Ether "10.0e18" + Supply Geoff Ether "3e18" + Assert Success + FastForward 2 Blocks + Assert Equal (SupplyBalance Geoff Ether) (Exactly "6.0e18") -- 3 * ( 1 + 2 * .5 ) + FastForward 2 Blocks + Assert Equal (SupplyBalance Geoff Ether) (Exactly "9.0e18") -- 3 * ( 1 + 4 * .5 ) + Supply Geoff Ether "1e18" + Assert Equal (SupplyBalance Geoff Ether) (Exactly "10.0e18") -- 3 * ( 1 + 4 * .5 ) + 1 + FastForward 2 Blocks + Assert Equal (SupplyBalance Geoff Ether) (Exactly "20.0e18") -- 10 * ( 1 + 2 * .5 ) + +Test "Geoff supplies Ether, Torrey supplies Ether and then Geoff supplies more Ether" + AddToken Ether + SupportMarket Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Geoff Ether "10.0e18" + Faucet Geoff Ether "10.0e18" + Approve Torrey Ether "5.0e18" + Faucet Torrey Ether "5.0e18" + Supply Geoff Ether "1e18" + Assert Success + FastForward 2 Blocks + Assert Equal (SupplyBalance Geoff Ether) (Exactly "2.0e18") + Supply Torrey Ether "3e18" + Assert Success + FastForward 2 Blocks + Assert Equal (SupplyBalance Torrey Ether) (Exactly "6.0e18") + Assert Equal (SupplyBalance Geoff Ether) (Exactly "4.0e18") + Supply Geoff Ether "1e18" + Assert Equal (SupplyBalance Geoff Ether) (Exactly "5.0e18") + +Test "Can't supply an 'initial' asset" + AddToken Dragon + Approve Geoff Dragon "10.0e18" + Faucet Geoff Dragon "10.0e18" + Supply Geoff Dragon "1e18" + Assert Failure MARKET_NOT_LISTED SUPPLY_MARKET_NOT_LISTED + +Test "Can't supply when contract is paused" + AddToken Ether + SupportMarket Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Geoff Ether 1.0e18 + Faucet Geoff Ether 0.4e18 + PolicyHook Ether (SetPaused True) + Supply Geoff Ether 0.3e18 + Assert Failure COMPTROLLER_REJECTION SUPPLY_COMPTROLLER_REJECTION 1 + Assert Equal (SupplyBalance Geoff Ether) (Exactly "0e18") + +Test "With always paused policy hook, can't supply when contract is paused" + AddToken Ether + SupportMarket Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) AlwaysPausedPolicyHook + Supply Geoff Ether 0.3e18 + Assert Failure COMPTROLLER_REJECTION SUPPLY_COMPTROLLER_REJECTION 99 diff --git a/spec/scenario/TokenTransfer.scen b/spec/scenario/TokenTransfer.scen new file mode 100644 index 000000000..1c5b01d4b --- /dev/null +++ b/spec/scenario/TokenTransfer.scen @@ -0,0 +1,86 @@ + +Test "Simple cToken Transfer" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff Some ZRX cZRX + Mint Geoff 50e18 cZRX + -- Just to be sure, check initial balances + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 50e9) + Assert Equal (Erc20 cZRX TokenBalance Torrey) Zero + -- Just transfer + Transfer Geoff Torrey 10e9 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 40e9) + Assert Equal (Erc20 cZRX TokenBalance Torrey) (Exactly 10e9) + +Test "Simple cToken Transfer When Underlying Paused" + NewComptroller + ListedCToken WBTC cWBTC initialExchangeRate:0.1 tokenType:WBTC + Prep Geoff Some WBTC cWBTC + Mint Geoff 50e8 cWBTC + -- Just to be sure, check initial balances + Assert Equal (Erc20 cWBTC TokenBalance Geoff) (Exactly 50e9) + Assert Equal (Erc20 cWBTC TokenBalance Torrey) Zero + -- Just transfer + Erc20 WBTC Pause + Transfer Geoff Torrey 10e9 cWBTC + Assert Equal (Erc20 cWBTC TokenBalance Geoff) (Exactly 40e9) + Assert Equal (Erc20 cWBTC TokenBalance Torrey) (Exactly 10e9) + +Test "Simple cToken Transfer 1:1 Rate" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e0 + Prep Geoff Some ZRX cZRX + Mint Geoff 50e18 cZRX + -- Just to be sure, check initial balances + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 50e18) + Assert Equal (Erc20 cZRX TokenBalance Torrey) Zero + -- Just transfer + Transfer Geoff Torrey 10e18 cZRX + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 40e18) + Assert Equal (Erc20 cZRX TokenBalance Torrey) (Exactly 10e18) + +Test "Simple cToken Transfer Not Allowed by Comptroller" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e0 + Comptroller SetCollateralFactor cZRX 0.1 + EnterMarkets Geoff cZRX + Prep Geoff Some ZRX cZRX + Mint Geoff 50e18 cZRX + -- Just to be sure, check initial balances + Invariant Remains (Erc20 cZRX TokenBalance Geoff) (Exactly 50e18) + Invariant Remains (Erc20 cZRX TokenBalance Torrey) Zero + -- Just transfer + AllowFailures + Transfer Geoff Torrey 60e18 cZRX + Assert Failure COMPTROLLER_REJECTION TRANSFER_COMPTROLLER_REJECTION INSUFFICIENT_LIQUIDITY + +Test "Simple cToken Transfer From" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff Some ZRX cZRX + Mint Geoff 50e18 cZRX + -- Just to be sure, check initial balances + Invariant Remains (Erc20 cZRX TokenBalance Torrey) Zero + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 50e9) + Assert Equal (Erc20 cZRX TokenBalance Coburn) Zero + -- Add approval + From Geoff (Erc20 cZRX Approve Torrey 25e9) + Assert Equal (Erc20 cZRX Allowance Geoff Torrey) (Exactly 25e9) + -- Perform transfer from + From Torrey (Erc20 cZRX TransferFrom Geoff Coburn 10e9) + Assert Equal (Erc20 cZRX TokenBalance Geoff) (Exactly 40e9) + Assert Equal (Erc20 cZRX TokenBalance Coburn) (Exactly 10e9) + Assert Equal (Erc20 cZRX Allowance Geoff Torrey) (Exactly 15e9) + +Test "cToken Transfer From Not Allowed" + NewComptroller + ListedCToken ZRX cZRX initialExchangeRate:1e9 + Prep Geoff Some ZRX cZRX + Mint Geoff 50e18 cZRX + -- + Invariant Remains (Erc20 cZRX TokenBalance Geoff) (Exactly 50e9) + Invariant Remains (Erc20 cZRX TokenBalance Torrey) (Exactly 0e9) + AllowFailures + Erc20 cZRX TransferFrom Geoff Torrey 10e9 + Assert Failure MATH_ERROR TRANSFER_NOT_ALLOWED + diff --git a/spec/scenario/Unitroller.scen b/spec/scenario/Unitroller.scen new file mode 100644 index 000000000..941d0299b --- /dev/null +++ b/spec/scenario/Unitroller.scen @@ -0,0 +1,59 @@ + +Test "Standard Upgrade" + Unitroller Deploy + PriceOracle Deploy Fixed 1.0 + ComptrollerImpl Deploy Scenario ScenComptroller + Unitroller SetPendingImpl ScenComptroller + ComptrollerImpl ScenComptroller Become (PriceOracle Address) 0.2 20 + Assert Equal (Comptroller CloseFactor) 0.2 + Assert Equal (Comptroller MaxAssets) 20 + Assert Equal (Comptroller Implementation) (Address ScenComptroller) + +Test "Once become, can become again" + Unitroller Deploy + PriceOracle Deploy Fixed 1.0 + ComptrollerImpl Deploy Scenario ScenComptroller + Unitroller SetPendingImpl ScenComptroller + ComptrollerImpl ScenComptroller Become (PriceOracle Address) 0.2 20 + Assert Equal (Comptroller CloseFactor) 0.2 + Assert Equal (Comptroller MaxAssets) 20 + Assert Equal (Comptroller Implementation) (Address ScenComptroller) + ComptrollerImpl Deploy Scenario ScenComptroller2 + Unitroller SetPendingImpl ScenComptroller2 + ComptrollerImpl ScenComptroller2 Become (PriceOracle Address) 0.4 40 + Assert Equal (Comptroller CloseFactor) 0.4 + Assert Equal (Comptroller MaxAssets) 40 + Assert Equal (Comptroller Implementation) (Address ScenComptroller2) + +Test "Recome has default values" + Unitroller Deploy + PriceOracle Deploy Fixed 1.0 + ComptrollerImpl Deploy Scenario ScenComptroller + Unitroller SetPendingImpl ScenComptroller + ComptrollerImpl ScenComptroller Recome + Assert Equal (Comptroller CloseFactor) 0.0 + Assert Equal (Comptroller MaxAssets) 0 + Assert Equal (Comptroller Implementation) (Address ScenComptroller) + +Test "Bork and unbork" + Unitroller Deploy + PriceOracle Deploy Fixed 1.0 + ComptrollerImpl Deploy Scenario ScenComptroller + -- Set a normal impl + Unitroller SetPendingImpl ScenComptroller + ComptrollerImpl ScenComptroller Become (PriceOracle Address) 0.2 20 + Assert Equal (Comptroller CloseFactor) 0.2 + Assert Equal (Comptroller MaxAssets) 20 + Assert Equal (Comptroller Implementation) (Address ScenComptroller) + -- Now move to a borked one that's bad + ComptrollerImpl Deploy Borked MyBork + Unitroller SetPendingImpl MyBork + ComptrollerImpl MyBork Become (PriceOracle Address) 0.4 40 + Assert ReadRevert (Comptroller CloseFactor) "revert" + Assert Equal (Comptroller Implementation) (Address MyBork) + -- Now change back to the first good one + Unitroller SetPendingImpl ScenComptroller + ComptrollerImpl ScenComptroller Recome + Assert Equal (Comptroller CloseFactor) 0.2 + Assert Equal (Comptroller MaxAssets) 20 + Assert Equal (Comptroller Implementation) (Address ScenComptroller) diff --git a/spec/scenario/Withdraw.scen.old b/spec/scenario/Withdraw.scen.old new file mode 100644 index 000000000..d6058ce4d --- /dev/null +++ b/spec/scenario/Withdraw.scen.old @@ -0,0 +1,48 @@ +-- Withdraw Tests + +Test "Supply Ether 5 then Withdraw MAX in the same block" + AddToken Ether -- baseline sanity check for withdraw max + SupportMarket Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Geoff Ether "6.0e18" + Faucet Geoff Ether "6.0e18" + Supply Geoff Ether "5.0e18" + Assert Success + Assert Equal (SupplyBalance Geoff Ether) (Exactly "5.0e18") + Assert Equal (BorrowBalance Geoff Ether) (Exactly "0e18") + Assert Equal (MaxBorrow Geoff) (Exactly "2.5e18") + Withdraw Geoff Ether "MAX" + Assert Success + Assert Equal (SupplyBalance Geoff Ether) (Exactly "0.0e18") + Assert Equal (TokenBalance Geoff Ether) (Exactly "6e18") + +Test "Supply Ether 5 then Withdraw MAX (6) after accruing some interest" + AddToken Ether + SupportMarket Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Geoff Ether "6.0e18" + Faucet Geoff Ether "6.0e18" + Supply Geoff Ether "5.0e18" -- We need more Ether in the system to simulate protocol gaining borrow interest to pay Geoff + Approve Torrey Ether "10.0e18" + Faucet Torrey Ether "10.0e18" + Supply Torrey Ether "10.0e18" + Assert Success + Assert Equal (SupplyBalance Geoff Ether) (Exactly "5.0e18") + FastForward 2 Blocks + Assert Equal (SupplyBalance Geoff Ether) (Exactly "10.0e18") + Withdraw Geoff Ether "MAX" + Assert Success + Assert Equal (SupplyBalance Geoff Ether) (Exactly "0.0e18") + Assert Equal (TokenBalance Geoff Ether) (Exactly "11e18") + +Test "Withdraw Ether 1 when contract paused" + AddToken Ether + SupportMarket Ether (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Approve Geoff Ether "1.0e18" + Faucet Geoff Ether "1.0e18" + Supply Geoff Ether "1.0e18" + Assert Success + Assert Equal (SupplyBalance Geoff Ether) (Exactly "1.0e18") + PolicyHook Ether (SetPaused True) + Withdraw Geoff Ether "1.0e18" + Assert Failure COMPTROLLER_REJECTION WITHDRAW_COMPTROLLER_REJECTION 1 + Assert Equal (SupplyBalance Geoff Ether) (Exactly "1e18") + Assert Equal (TokenBalance Geoff Ether) (Exactly "0e18") diff --git a/spec/scenario/admin/setMarketPolicyHook.scen.old b/spec/scenario/admin/setMarketPolicyHook.scen.old new file mode 100644 index 000000000..8af26633b --- /dev/null +++ b/spec/scenario/admin/setMarketPolicyHook.scen.old @@ -0,0 +1,41 @@ + +-- Tests for MoneyMarket's `_setMarketPolicyHook(address,address)` function + +Macro ListAsset asset + SupportMarket asset (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Assert Success + +Test "emits log on failure due to non-admin caller" + AddToken Ether + Invariant Static (GetMarketPolicyHook Ether) + From Geoff (SetMarketPolicyHook Ether SimplePolicyHook) + Assert Failure UNAUTHORIZED SET_POLICY_HOOK_OWNER_CHECK + +Test "emits log on failure due to not-listed market" + AddToken Ether + Invariant Static (GetMarketPolicyHook Ether) + SetMarketPolicyHook Ether SimplePolicyHook + Assert Failure MARKET_NOT_LISTED SET_POLICY_HOOK_MARKET_NOT_LISTED + +Test "emits log on failure due to being a bad policy hook" + AddToken Ether + ListAsset Ether + Invariant Static (GetMarketPolicyHook Ether) + SetMarketPolicyHook Ether FakePolicyHook + Assert Failure BAD_INPUT SET_POLICY_HOOK_IS_NOT_POLICY_HOOK + +Test "reverts due to not being a policy hook" + AddToken Ether + ListAsset Ether + Invariant Static (GetMarketPolicyHook Ether) + SetMarketPolicyHook Ether NotPolicyHook + Assert Revert + +Test "successfully sets policy hook" + AddToken Ether + ListAsset Ether + SetMarketPolicyHook Ether SimplePolicyHook + Assert Success + Assert Equal (GetMarketPolicyHook Ether) LastContract + Assert Log "PolicyHookChanged" \ + ("asset" (Address Ether)) ("oldPolicyHook" Anything) ("newPolicyHook" (LastContract)) diff --git a/spec/scenario/admin/setMarketPriceOracle.scen.old b/spec/scenario/admin/setMarketPriceOracle.scen.old new file mode 100644 index 000000000..01ba45d6a --- /dev/null +++ b/spec/scenario/admin/setMarketPriceOracle.scen.old @@ -0,0 +1,38 @@ + +-- Tests for MoneyMarket's `_setMarketPriceOracle(address,address)` function + +Macro ListAsset asset + SupportMarket asset (FixedPrice 1.0) (FixedRate 0.5 0.75) SimplePolicyHook + Assert Success + +Test "is initially unset" + AddToken Ether + Assert Equal (GetMarketPriceOracle Ether) (Exactly 0) + +Test "fails if not called by admin" + AddToken Ether + Invariant Static (GetMarketPriceOracle Ether) + From Geoff (SetMarketPriceOracle Ether Simple) + Assert Failure UNAUTHORIZED SET_ORACLE_OWNER_CHECK + +Test "fails if market not listed" + AddToken Ether + Invariant Static (GetMarketPriceOracle Ether) + SetMarketPriceOracle Ether Simple + Assert Failure MARKET_NOT_LISTED SET_ORACLE_MARKET_NOT_LISTED + +Test "reverts if new address is not really an oracle" + AddToken Ether + ListAsset Ether + Invariant Static (GetMarketPriceOracle Ether) + SetMarketPriceOracle Ether NotPriceOracle + Assert Revert + +Test "successfully set by admin" + AddToken Ether + ListAsset Ether + SetMarketPriceOracle Ether Simple + Assert Success + Assert Equal (GetMarketPriceOracle Ether) LastContract + Assert Log "NewMarketOracle" \ + ("asset" (Address Ether)) ("oldPriceOracle" Anything) ("newPriceOracle" (LastContract)) diff --git a/test/CarefulMathTest.sol b/test/CarefulMathTest.sol new file mode 100644 index 000000000..a9ff3291e --- /dev/null +++ b/test/CarefulMathTest.sol @@ -0,0 +1,167 @@ +pragma solidity ^0.5.8; + +import "truffle/Assert.sol"; +import "../contracts/CarefulMath.sol"; + +contract CarefulMathTest is CarefulMath { + + function testStandardAddition() public { + (MathError err, uint val) = addUInt(5, 6); + + assertNoError(err); + Assert.equal(11, val, "should compute addition correctly"); + } + + function testAddZeroLeft() public { + (MathError err, uint val) = addUInt(0, 6); + + assertNoError(err); + Assert.equal(6, val, "should compute addition correctly"); + } + + function testAddZeroRight() public { + (MathError err, uint val) = addUInt(6, 0); + + assertNoError(err); + Assert.equal(6, val, "should compute addition correctly"); + } + + function testAdditiveOverflow() public { + (MathError err, uint val) = addUInt(5, uint(-1)); + + assertError(MathError.INTEGER_OVERFLOW, err, "should have error INTEGER_OVERFLOW"); + Assert.equal(0, val, "should have default value"); + } + + function testStandardSubtraction() public { + (MathError err, uint val) = subUInt(1000, 250); + + assertNoError(err); + Assert.equal(750, val, "should compute subtraction correctly"); + } + + function testSubtractZero() public { + (MathError err, uint val) = subUInt(1000, 0); + + assertNoError(err); + Assert.equal(1000, val, "should compute subtraction correctly"); + } + + function testSubtractFromZero() public { + (MathError err, uint val) = subUInt(0, 1000); + + assertError(MathError.INTEGER_UNDERFLOW, err, "should have error INTEGER_UNDERFLOW"); + Assert.equal(0, val, "should compute subtraction correctly"); + } + + function testSubtractiveUnderflow() public { + (MathError err, uint val) = subUInt(250, 1000); + + assertError(MathError.INTEGER_UNDERFLOW, err, "should have error INTEGER_UNDERFLOW"); + Assert.equal(0, val, "should compute subtraction correctly"); + } + + function testStandardMultiplication() public { + (MathError err, uint val) = mulUInt(100, 7); + + assertNoError(err); + Assert.equal(700, val, "should compute multiplication correctly"); + } + + function testStandardMultiplicationByZeroLeft() public { + (MathError err, uint val) = mulUInt(0, 100); + + assertNoError(err); + Assert.equal(0, val, "should compute multiplication correctly"); + } + + function testStandardMultiplicationByZeroRight() public { + (MathError err, uint val) = mulUInt(100, 0); + + assertNoError(err); + Assert.equal(0, val, "should compute multiplication correctly"); + } + + function testMultiplicativeOverflow() public { + (MathError err, uint val) = mulUInt(uint(-1), 3); + + assertError(MathError.INTEGER_OVERFLOW, err, "should have error INTEGER_OVERFLOW"); + Assert.equal(0, val, "should have default value"); + } + + function testLargeNumberIdentityMultiplication() public { + (MathError err, uint val) = mulUInt(uint(-1), 1); + + assertNoError(err); + Assert.equal(uint(-1), val, "should compute multiplication correctly"); + } + + function testStandardDivision() public { + (MathError err, uint val) = divUInt(100, 5); + + assertNoError(err); + Assert.equal(20, val, "should compute division correctly"); + } + + function testDivisionWithTruncation() public { + (MathError err, uint val) = divUInt(100, 33); + + assertNoError(err); + Assert.equal(3, val, "should compute division correctly"); + } + + function testDivisionOfZero() public { + (MathError err, uint val) = divUInt(0, 8); + + assertNoError(err); + Assert.equal(0, val, "should compute division correctly"); + } + + function testDivisionByZero() public { + (MathError err, uint val) = divUInt(8, 0); + + assertError(MathError.DIVISION_BY_ZERO, err, "should have error DIVISION_BY_ZERO"); + Assert.equal(0, val, "should have default value"); + } + + function testLargeNumberIdentityDivision() public { + (MathError err, uint val) = divUInt(uint(-1), 1); + + assertNoError(err); + Assert.equal(uint(-1), val, "should compute multiplication correctly"); + } + + + function testAddThenSub() public { + (MathError err, uint val) = addThenSubUInt(1, 3, 2); + + assertNoError(err); + Assert.equal(2, val, "should perform operations in the stated order"); // 1 - 2 before adding 3 would underflow + } + + function testAddThenSubOverflow() public { + (MathError err, uint val) = addThenSubUInt(2**256 - 1, 2**256 - 1, 5); + assertError(MathError.INTEGER_OVERFLOW, err, "should have error INTEGER_OVERFLOW"); + + Assert.equal(0, val, "should have default value"); + } + + function testAddThenSubUnderflow() public { + (MathError err, uint val) = addThenSubUInt(1, 2, 5); + assertError(MathError.INTEGER_UNDERFLOW, err, "should have error INTEGER_UNDERFLOW"); + + Assert.equal(0, val, "should have default value"); + } + + function assertError(MathError expected, MathError given, string memory message) internal { + Assert.equal(uint(expected), uint(given), message); + } + + function assertNoError(MathError err) internal { + assertError(MathError.NO_ERROR, err, "should have error NO_ERROR"); + } + + function assertZero(uint value, string memory message) internal { + Assert.equal(0, value, message); + } +} \ No newline at end of file diff --git a/test/Comptroller/accountLiquidityTest.js b/test/Comptroller/accountLiquidityTest.js new file mode 100644 index 000000000..3390d9472 --- /dev/null +++ b/test/Comptroller/accountLiquidityTest.js @@ -0,0 +1,117 @@ +const {call, send} = require('../Utils/MochaTruffle'); +const { + makeComptroller, + makeCToken, + enterMarkets, + quickMint +} = require('../Utils/Compound'); + +contract('Comptroller', ([root, ...accounts]) => { + describe('liquidity', () => { + it("fails if a price has not been set", async () => { + const cToken = await makeCToken({supportMarket: true}); + await enterMarkets([cToken], accounts[1]); + assert.hasTrollError(await call(cToken.comptroller, 'getAccountLiquidity', [accounts[1]]), 'PRICE_ERROR'); + }); + + it("allows a borrow up to collateralFactor, but not more", async () => { + const collateralFactor = 0.5, underlyingPrice = 1, user = accounts[1], amount = 1e6; + const cToken = await makeCToken({supportMarket: true, collateralFactor, underlyingPrice}); + + let error, liquidity, shortfall; + + // not in market yet, hypothetical borrow should have no effect + ({1: liquidity, 2: shortfall} = await call(cToken.comptroller, 'getHypotheticalAccountLiquidity', [user, cToken._address, 0, amount])); + assert.equal(liquidity, 0); + assert.equal(shortfall, 0); + + await enterMarkets([cToken], user); + await quickMint(cToken, user, amount); + + // total account liquidity after supplying `amount` + ({1: liquidity, 2: shortfall} = await call(cToken.comptroller, 'getAccountLiquidity', [user])); + assert.equal(liquidity, amount * collateralFactor); + assert.equal(shortfall, 0); + + // hypothetically borrow `amount`, should shortfall over collateralFactor + ({1: liquidity, 2: shortfall} = await call(cToken.comptroller, 'getHypotheticalAccountLiquidity', [user, cToken._address, 0, amount])); + assert.equal(liquidity, 0); + assert.equal(shortfall, amount * (1 - collateralFactor)); + + // hypothetically redeem `amount`, should be back to even + ({1: liquidity, 2: shortfall} = await call(cToken.comptroller, 'getHypotheticalAccountLiquidity', [user, cToken._address, amount, 0])); + assert.equal(liquidity, 0); + assert.equal(shortfall, 0); + }); + + it("allows entering 3 markets, supplying to 2 and borrowing up to collateralFactor in the 3rd", async () => { + const amount1 = 1e6, amount2 = 1e3, user = accounts[1]; + const cf1 = 0.5, cf2 = 0.666, cf3 = 0, up1 = 3, up2 = 2.718, up3 = 1; + const c1 = amount1 * cf1 * up1, c2 = amount2 * cf2 * up2, collateral = Math.floor(c1 + c2); + const cToken1 = await makeCToken({supportMarket: true, collateralFactor: cf1, underlyingPrice: up1}); + const cToken2 = await makeCToken({supportMarket: true, comptroller: cToken1.comptroller, collateralFactor: cf2, underlyingPrice: up2}); + const cToken3 = await makeCToken({supportMarket: true, comptroller: cToken1.comptroller, collateralFactor: cf3, underlyingPrice: up3}); + + await enterMarkets([cToken1, cToken2, cToken3], user); + await quickMint(cToken1, user, amount1); + await quickMint(cToken2, user, amount2); + + let error, liquidity, shortfall; + + ({0: error, 1: liquidity, 2: shortfall} = await call(cToken3.comptroller, 'getAccountLiquidity', [user])); + assert.equal(error, 0); + assert.equal(liquidity, collateral); + assert.equal(shortfall, 0); + + ({1: liquidity, 2: shortfall} = await call(cToken3.comptroller, 'getHypotheticalAccountLiquidity', [user, cToken3._address, Math.floor(c2), 0])); + assert.equal(liquidity, collateral); + assert.equal(shortfall, 0); + + ({1: liquidity, 2: shortfall} = await call(cToken3.comptroller, 'getHypotheticalAccountLiquidity', [user, cToken3._address, 0, Math.floor(c2)])); + assert.equal(liquidity, c1); + assert.equal(shortfall, 0); + + ({1: liquidity, 2: shortfall} = await call(cToken3.comptroller, 'getHypotheticalAccountLiquidity', [user, cToken3._address, 0, collateral + c1])); + assert.equal(liquidity, 0); + assert.equal(shortfall, c1); + + ({1: liquidity, 2: shortfall} = await call(cToken1.comptroller, 'getHypotheticalAccountLiquidity', [user, cToken1._address, amount1, 0])); + assert.equal(liquidity, Math.floor(c2)); + assert.equal(shortfall, 0); + }); + }); + + describe("getAccountLiquidity", async () => { + it("returns 0 if not 'in' any markets", async () => { + const comptroller = await makeComptroller(); + const {0: error, 1: liquidity, 2: shortfall} = await call(comptroller, 'getAccountLiquidity', [accounts[0]]); + assert.equal(0, error, "error should be zero"); + assert.equal(0, liquidity, "liquidity should be zero"); + assert.equal(0, shortfall, "shortfall should be zero"); + }); + }); + + describe("getHypotheticalAccountLiquidity", async () => { + it("returns 0 if not 'in' any markets", async () => { + const cToken = await makeCToken(); + const {0: error, 1: liquidity, 2: shortfall} = await call(cToken.comptroller, 'getHypotheticalAccountLiquidity', [accounts[0], cToken._address, 0, 0]); + assert.equal(0, error, "error should be zero"); + assert.equal(0, liquidity, "liquidity should be zero"); + assert.equal(0, shortfall, "shortfall should be zero"); + }); + + it("returns collateral factor times dollar amount of tokens minted in a single market", async () => { + const collateralFactor = 0.5, exchangeRate = 1, underlyingPrice = 1; + const cToken = await makeCToken({supportMarket: true, collateralFactor, exchangeRate, underlyingPrice}); + const from = accounts[0], balance = 1e7, amount = 1e6; + await enterMarkets([cToken], from); + await send(cToken.underlying, 'harnessSetBalance', [from, balance], {from}); + await send(cToken.underlying, 'approve', [cToken._address, balance], {from}); + await send(cToken, 'mint', [amount], {from}); + const {0: error, 1: liquidity, 2: shortfall} = await call(cToken.comptroller, 'getHypotheticalAccountLiquidity', [from, cToken._address, 0, 0]); + assert.equal(0, error, "error should be zero"); + assert.equal(liquidity, amount * collateralFactor * exchangeRate * underlyingPrice, "liquidity should be 5e5"); + assert.equal(shortfall, 0, "shortfall should be zero"); + }); + }); +}); \ No newline at end of file diff --git a/test/Comptroller/adminTest.js b/test/Comptroller/adminTest.js new file mode 100644 index 000000000..adfaba7a8 --- /dev/null +++ b/test/Comptroller/adminTest.js @@ -0,0 +1,110 @@ +const {address, getContract, call, send} = require('../Utils/MochaTruffle'); + +const Unitroller = getContract('Unitroller'); + +contract('admin / _setPendingAdmin / _acceptAdmin', function([root, ...accounts]) { + let comptroller; + beforeEach(async () => { + comptroller = await Unitroller.deploy().send({from: root}); + }); + + describe('admin()', async () => { + it('should return correct admin', async () => { + assert.equal(await call(comptroller, 'admin'), root); + }); + }); + + describe('pendingAdmin()', async () => { + it('should return correct pending admin', async () => { + assert.addressZero(await call(comptroller, 'pendingAdmin')) + }); + }); + + describe('_setPendingAdmin()', async () => { + it('should only be callable by admin', async () => { + assert.hasTrollFailure( + await send(comptroller, '_setPendingAdmin', [accounts[0]], {from: accounts[0]}), + 'UNAUTHORIZED', + 'SET_PENDING_ADMIN_OWNER_CHECK' + ); + + // Check admin stays the same + assert.equal(await call(comptroller, 'admin'), root); + assert.addressZero(await call(comptroller, 'pendingAdmin')); + }); + + it('should properly set pending admin', async () => { + assert.success(await send(comptroller, '_setPendingAdmin', [accounts[0]])); + + // Check admin stays the same + assert.equal(await call(comptroller, 'admin'), root); + assert.equal(await call(comptroller, 'pendingAdmin'), accounts[0]); + }); + + it('should properly set pending admin twice', async () => { + assert.success(await send(comptroller, '_setPendingAdmin', [accounts[0]])); + assert.success(await send(comptroller, '_setPendingAdmin', [accounts[1]])); + + // Check admin stays the same + assert.equal(await call(comptroller, 'admin'), root); + assert.equal(await call(comptroller, 'pendingAdmin'), accounts[1]); + }); + + it('should emit event', async () => { + const result = await send(comptroller, '_setPendingAdmin', [accounts[0]]); + assert.hasLog(result, 'NewPendingAdmin', { + oldPendingAdmin: address(0), + newPendingAdmin: accounts[0], + }); + }); + }); + + describe('_acceptAdmin()', async () => { + it('should fail when pending admin is zero', async () => { + assert.hasTrollFailure( + await send(comptroller, '_acceptAdmin'), + 'UNAUTHORIZED', + 'ACCEPT_ADMIN_PENDING_ADMIN_CHECK' + ); + + // Check admin stays the same + assert.equal(await call(comptroller, 'admin'), root); + assert.addressZero(await call(comptroller, 'pendingAdmin')); + }); + + it('should fail when called by another account (e.g. root)', async () => { + assert.success(await send(comptroller, '_setPendingAdmin', [accounts[0]])); + assert.hasTrollFailure( + await send(comptroller, '_acceptAdmin'), + 'UNAUTHORIZED', + 'ACCEPT_ADMIN_PENDING_ADMIN_CHECK' + ); + + // Check admin stays the same + assert.equal(await call(comptroller, 'admin'), root); + assert.equal(await call(comptroller, 'pendingAdmin'), accounts[0]); + }); + + it('should succeed and set admin and clear pending admin', async () => { + assert.success(await send(comptroller, '_setPendingAdmin', [accounts[0]])); + assert.success(await send(comptroller, '_acceptAdmin', [], {from: accounts[0]})); + + // Check admin stays the same + assert.equal(await call(comptroller, 'admin'), accounts[0]); + assert.addressZero(await call(comptroller, 'pendingAdmin')); + }); + + it('should emit log on success', async () => { + assert.success(await send(comptroller, '_setPendingAdmin', [accounts[0]])); + const result = await send(comptroller, '_acceptAdmin', [], {from: accounts[0]}); + assert.hasLog(result, 'NewAdmin', { + oldAdmin: root, + newAdmin: accounts[0], + }); + assert.hasLog(result, 'NewPendingAdmin', { + oldPendingAdmin: accounts[0], + newPendingAdmin: address(0), + }); + }); + }); +}); diff --git a/test/Comptroller/assetsListTest.js b/test/Comptroller/assetsListTest.js new file mode 100644 index 000000000..7e5c0c92f --- /dev/null +++ b/test/Comptroller/assetsListTest.js @@ -0,0 +1,186 @@ +const {both, call, send} = require('../Utils/MochaTruffle'); +const { + makeComptroller, + makeCToken +} = require('../Utils/Compound'); + +contract('assetListTest', function([root, customer, ...accounts]) { + let comptroller; + let allTokens, OMG, ZRX, BAT, REP, DAI, SKT; + + beforeEach(async () => { + comptroller = await makeComptroller({maxAssets: 10}); + allTokens = [OMG, ZRX, BAT, REP, DAI, SKT] = await Promise.all( + ['OMG', 'ZRX', 'BAT', 'REP', 'DAI', 'sketch'] + .map(async (name) => makeCToken({comptroller, name, symbol: name, supportMarket: name != 'sketch', underlyingPrice: 0.5})) + ); + }); + + describe('_setMaxAssets', async () => { + it("fails if called by a non-admin", async () => { + assert.hasTrollFailure( + await send(comptroller, '_setMaxAssets', [15], {from: customer}), + 'UNAUTHORIZED', + 'SET_MAX_ASSETS_OWNER_CHECK' + ); + assert.equal(await call(comptroller, 'maxAssets'), 10); + }); + + it("succeeds if called by an admin", async() => { + assert.hasLog( + await send(comptroller, '_setMaxAssets', [15]), + 'NewMaxAssets', { + oldMaxAssets: "10", + newMaxAssets: "15" + }); + assert.equal(await call(comptroller, 'maxAssets'), 15); + }); + }); + + async function checkMarkets(expectedTokens) { + for (let token of allTokens) { + const isExpected = expectedTokens.some(e => e.symbol == token.symbol); + assert.equal(await call(comptroller, 'checkMembership', [customer, token._address]), isExpected, `expected ${token.symbol} ${isExpected}`); + } + } + + async function enterAndCheckMarkets(enterTokens, expectedTokens, expectedErrors = null) { + const {reply, receipt} = await both(comptroller, 'enterMarkets', [enterTokens.map(t => t._address)], {from: customer}); + const assetsIn = await call(comptroller, 'getAssetsIn', [customer]); + assert.each('hasTrollError', reply, expectedErrors || enterTokens.map(_ => 'NO_ERROR')); + assert.trollSuccess(receipt); + assert.deepEqual(assetsIn, expectedTokens.map(t => t._address), 'should match expected markets'); + await checkMarkets(expectedTokens); + return receipt; + }; + + async function exitAndCheckMarkets(exitToken, expectedTokens, expectedError = 'NO_ERROR') { + const {reply, receipt} = await both(comptroller, 'exitMarket', [exitToken._address], {from: customer}); + const assetsIn = await call(comptroller, 'getAssetsIn', [customer]); + assert.hasTrollError(reply, expectedError); + //assert.trollSuccess(receipt); XXX enterMarkets cannot fail, but exitMarket can - kind of confusing + assert.deepEqual(assetsIn, expectedTokens.map(t => t._address), 'should match expected markets'); + await checkMarkets(expectedTokens); + return receipt; + }; + + describe('enterMarkets', async () => { + it("properly emits events", async () => { + const result1 = await enterAndCheckMarkets([OMG], [OMG]); + const result2 = await enterAndCheckMarkets([OMG], [OMG]); + assert.hasLog( + result1, + 'MarketEntered', { + cToken: OMG._address, + account: customer + }); + assert.deepEqual(result2.events, {}, "should have no events"); + }); + + it("adds to the asset list only once", async () => { + await enterAndCheckMarkets([OMG], [OMG]); + await enterAndCheckMarkets([OMG], [OMG]); + await enterAndCheckMarkets([ZRX, BAT, OMG], [OMG, ZRX, BAT]); + await enterAndCheckMarkets([ZRX, OMG], [OMG, ZRX, BAT]); + await enterAndCheckMarkets([ZRX], [OMG, ZRX, BAT]); + await enterAndCheckMarkets([OMG], [OMG, ZRX, BAT]); + await enterAndCheckMarkets([ZRX], [OMG, ZRX, BAT]); + await enterAndCheckMarkets([BAT], [OMG, ZRX, BAT]); + }); + + it("the market must be listed for add to succeed", async () => { + await enterAndCheckMarkets([SKT], [], ['MARKET_NOT_LISTED']); + await send(comptroller, '_supportMarket', [SKT._address]); + await enterAndCheckMarkets([SKT], [SKT]); + }); + + it("returns a list of codes mapping to user's ultimate membership in given addresses", async () => { + await enterAndCheckMarkets([OMG, ZRX, BAT], [OMG, ZRX, BAT], ['NO_ERROR', 'NO_ERROR', 'NO_ERROR'], "success if can enter markets"); + await enterAndCheckMarkets([OMG, SKT], [OMG, ZRX, BAT], ['NO_ERROR', 'MARKET_NOT_LISTED'], "error for unlisted markets"); + }); + + it("can enter one + asset cap reached", async () => { + await send(comptroller, '_setMaxAssets', [1]); + await enterAndCheckMarkets([ZRX, OMG], [ZRX], ['NO_ERROR', 'TOO_MANY_ASSETS'], "error if asset cap reached"); + }); + + it("reaches asset cap + already in asset", async () => { + await send(comptroller, '_setMaxAssets', [1]); + await enterAndCheckMarkets([ZRX], [ZRX]); + await enterAndCheckMarkets([OMG, ZRX], [ZRX], ['TOO_MANY_ASSETS', 'NO_ERROR'], "error if already in asset"); + }); + + describe('reaching the asset cap', async () => { + beforeEach(async () => { + await send(comptroller, '_setMaxAssets', [3]); + await enterAndCheckMarkets([OMG, ZRX, BAT], [OMG, ZRX, BAT]); + }); + + it("does not grow if user exactly at asset cap", async () => { + await send(comptroller, '_setMaxAssets', [3]); + await enterAndCheckMarkets([REP], [OMG, ZRX, BAT], ['TOO_MANY_ASSETS']); + await send(comptroller, '_setMaxAssets', [4]); + await enterAndCheckMarkets([REP], [OMG, ZRX, BAT, REP]); + await enterAndCheckMarkets([DAI], [OMG, ZRX, BAT, REP], ['TOO_MANY_ASSETS']); + }); + + it("does not grow if user is well beyond asset cap", async () => { + await send(comptroller, '_setMaxAssets', [1]); + await enterAndCheckMarkets([REP], [OMG, ZRX, BAT], ['TOO_MANY_ASSETS']); + }); + }); + }); + + describe('exitMarket', async () => { + it("doesn't let you exit if you have a borrow balance", async () => { + await enterAndCheckMarkets([OMG], [OMG]); + await send(OMG, 'harnessSetAccountBorrows', [customer, 1, 1]); + await exitAndCheckMarkets(OMG, [OMG], 'NONZERO_BORROW_BALANCE'); + }); + + it("rejects unless redeem allowed", async () => { + await enterAndCheckMarkets([OMG, BAT], [OMG, BAT]); + await send(BAT, 'harnessSetAccountBorrows', [customer, 1, 1]); + + // BAT has a negative balance and there's no supply, thus account should be underwater + await exitAndCheckMarkets(OMG, [OMG, BAT], 'REJECTION'); + }); + + it("accepts when you're not in the market already", async () => { + await enterAndCheckMarkets([OMG, BAT], [OMG, BAT]); + + // Not in ZRX, should exit fine + await exitAndCheckMarkets(ZRX, [OMG, BAT], 'NO_ERROR'); + }); + + it("properly removes when there's only one asset", async () => { + await enterAndCheckMarkets([OMG], [OMG]); + await exitAndCheckMarkets(OMG, [], 'NO_ERROR'); + }); + + it("properly removes when there's only two assets, removing the first", async () => { + await enterAndCheckMarkets([OMG, BAT], [OMG, BAT]); + await exitAndCheckMarkets(OMG, [BAT], 'NO_ERROR'); + }); + + it("properly removes when there's only two assets, removing the second", async () => { + await enterAndCheckMarkets([OMG, BAT], [OMG, BAT]); + await exitAndCheckMarkets(BAT, [OMG], 'NO_ERROR'); + }); + + it("properly removes when there's only three assets, removing the first", async () => { + await enterAndCheckMarkets([OMG, BAT, ZRX], [OMG, BAT, ZRX]); + await exitAndCheckMarkets(OMG, [ZRX, BAT], 'NO_ERROR'); + }); + + it("properly removes when there's only three assets, removing the second", async () => { + await enterAndCheckMarkets([OMG, BAT, ZRX], [OMG, BAT, ZRX]); + await exitAndCheckMarkets(BAT, [OMG, ZRX], 'NO_ERROR'); + }); + + it("properly removes when there's only three assets, removing the third", async () => { + await enterAndCheckMarkets([OMG, BAT, ZRX], [OMG, BAT, ZRX]); + await exitAndCheckMarkets(ZRX, [OMG, BAT], 'NO_ERROR'); + }); + }); +}); diff --git a/test/Comptroller/comptrollerTest.js b/test/Comptroller/comptrollerTest.js new file mode 100644 index 000000000..b183b58ba --- /dev/null +++ b/test/Comptroller/comptrollerTest.js @@ -0,0 +1,250 @@ +const { + etherMantissa, + both, + call, + send +} = require('../Utils/MochaTruffle'); + +const { + makeComptroller, + makePriceOracle, + makeCToken, + makeToken +} = require('../Utils/Compound'); + +contract('Comptroller', ([root, ...accounts]) => { + describe('constructor', () => { + it("on success it sets admin to creator and pendingAdmin is unset", async () => { + const comptroller = await makeComptroller(); + assert.equal(root, await call(comptroller, 'admin')); + assert.equal(0, await call(comptroller, 'pendingAdmin')); + }); + + it("on success it sets closeFactor and maxAssets as specified", async () => { + const comptroller = await makeComptroller(); + assert.equal(.051e18, await call(comptroller, 'closeFactorMantissa')); + assert.equal(10, await call(comptroller, 'maxAssets')); + }); + + it("reverts on invalid closeFactor", async () => { + await assert.revert(makeComptroller({closeFactor: 1}), 'revert set close factor error'); + }); + + it("allows small and large maxAssets", async () => { + const comptroller = await makeComptroller({maxAssets: 0}); + assert.equal(0, await call(comptroller, 'maxAssets')); + + // 5000 is an arbitrary number larger than what we expect to ever actually use + await send(comptroller, '_setMaxAssets', [5000]); + assert.equal(5000, await call(comptroller, 'maxAssets')); + }); + }); + + describe('_setLiquidationIncentive', async () => { + const initialIncentive = etherMantissa(1.0); + const validIncentive = etherMantissa(1.1); + const tooSmallIncentive = etherMantissa(0.99999); + const tooLargeIncentive = etherMantissa(1.50000001); + + let comptroller; + before(async () => { + comptroller = await makeComptroller(); + }); + + it("fails if called by non-admin", async () => { + const {reply, receipt} = await both(comptroller, '_setLiquidationIncentive', [initialIncentive], {from: accounts[0]}); + assert.hasTrollError(reply, 'UNAUTHORIZED'); + assert.hasTrollFailure( + receipt, + 'UNAUTHORIZED', + 'SET_LIQUIDATION_INCENTIVE_OWNER_CHECK' + ); + assert.equal(await call(comptroller, 'liquidationIncentiveMantissa'), initialIncentive); + }); + + it("fails if incentive is less than min", async () => { + const {reply, receipt} = await both(comptroller, '_setLiquidationIncentive', [tooSmallIncentive]); + assert.hasTrollError(reply, 'INVALID_LIQUIDATION_INCENTIVE'); + assert.hasTrollFailure( + receipt, + 'INVALID_LIQUIDATION_INCENTIVE', + 'SET_LIQUIDATION_INCENTIVE_VALIDATION' + ); + assert.equal(await call(comptroller, 'liquidationIncentiveMantissa'), initialIncentive); + }); + + it("fails if incentive is greater than max", async () => { + const {reply, receipt} = await both(comptroller, '_setLiquidationIncentive', [tooLargeIncentive]); + assert.hasTrollError(reply, 'INVALID_LIQUIDATION_INCENTIVE'); + assert.hasTrollFailure( + receipt, + 'INVALID_LIQUIDATION_INCENTIVE', + 'SET_LIQUIDATION_INCENTIVE_VALIDATION' + ); + assert.equal(await call(comptroller, 'liquidationIncentiveMantissa'), initialIncentive); + }); + + it("accepts a valid incentive and emits a NewLiquidationIncentive event", async () => { + const {reply, receipt} = await both(comptroller, '_setLiquidationIncentive', [validIncentive]); + assert.hasTrollError(reply, 'NO_ERROR'); + assert.hasLog(receipt, 'NewLiquidationIncentive', { + oldLiquidationIncentiveMantissa: initialIncentive.toString(), + newLiquidationIncentiveMantissa: validIncentive.toString() + }); + assert.equal(await call(comptroller, 'liquidationIncentiveMantissa'), validIncentive); + }); + }); + + describe('_setPriceOracle', async () => { + let comptroller, oldOracle, newOracle; + before(async () => { + comptroller = await makeComptroller(); + oldOracle = comptroller.priceOracle; + newOracle = await makePriceOracle(); + }); + + it("fails if called by non-admin", async () => { + assert.hasTrollFailure( + await send(comptroller, '_setPriceOracle', [newOracle._address], {from: accounts[0]}), + 'UNAUTHORIZED', + 'SET_PRICE_ORACLE_OWNER_CHECK' + ); + assert.equal(await comptroller.methods.oracle().call(), oldOracle._address); + }); + + it.skip("reverts if passed a contract that doesn't implement isPriceOracle", async () => { + await assert.revert(send(comptroller, '_setPriceOracle', [comptroller._address])); + assert.equal(await call(comptroller, 'oracle'), oldOracle._address); + }); + + it.skip("reverts if passed a contract that implements isPriceOracle as false", async () => { + await send(newOracle, 'setIsPriceOracle', [false]); // Note: not yet implemented + await assert.revert(send(notOracle, '_setPriceOracle', [comptroller._address]), "revert oracle method isPriceOracle returned false"); + assert.equal(await call(comptroller, 'oracle'), oldOracle._address); + }); + + it("accepts a valid price oracle and emits a NewPriceOracle event", async () => { + const result = await send(comptroller, '_setPriceOracle', [newOracle._address]); + assert.success(result); + assert.hasLog(result, 'NewPriceOracle', { + oldPriceOracle: oldOracle._address, + newPriceOracle: newOracle._address + }); + assert.equal(await call(comptroller, 'oracle'), newOracle._address); + }); + }); + + describe('_setCollateralFactor', async () => { + const half = etherMantissa(0.5), one = etherMantissa(1); + + it("fails if not called by admin", async () => { + const cToken = await makeCToken(); + assert.hasTrollFailure( + await send(cToken.comptroller, '_setCollateralFactor', [cToken._address, half], {from: accounts[0]}), + 'UNAUTHORIZED', + 'SET_COLLATERAL_FACTOR_OWNER_CHECK' + ); + }); + + it("fails if asset is not listed", async () => { + const cToken = await makeCToken(); + assert.hasTrollFailure( + await send(cToken.comptroller, '_setCollateralFactor', [cToken._address, half]), + 'MARKET_NOT_LISTED', + 'SET_COLLATERAL_FACTOR_NO_EXISTS' + ); + }); + + it("fails if factor is too high", async () => { + const cToken = await makeCToken({supportMarket: true}); + assert.hasTrollFailure( + await send(cToken.comptroller, '_setCollateralFactor', [cToken._address, one]), + 'INVALID_COLLATERAL_FACTOR', + 'SET_COLLATERAL_FACTOR_VALIDATION' + ); + }); + + it("fails if factor is set without an underlying price", async () => { + const cToken = await makeCToken({supportMarket: true}); + assert.hasTrollFailure( + await send(cToken.comptroller, '_setCollateralFactor', [cToken._address, half]), + 'PRICE_ERROR', + 'SET_COLLATERAL_FACTOR_WITHOUT_PRICE' + ); + }); + + it("succeeds and sets market", async () => { + const cToken = await makeCToken({supportMarket: true, underlyingPrice: 1}); + const result = await send(cToken.comptroller, '_setCollateralFactor', [cToken._address, half]); + assert.hasLog(result, 'NewCollateralFactor', { + cToken: cToken._address, + oldCollateralFactorMantissa: '0', + newCollateralFactorMantissa: half.toString() + }); + }); + }); + + describe('_supportMarket', async () => { + it("fails if not called by admin", async () => { + const cToken = await makeCToken(root); + assert.hasTrollFailure( + await send(cToken.comptroller, '_supportMarket', [cToken._address], {from: accounts[0]}), + 'UNAUTHORIZED', + 'SUPPORT_MARKET_OWNER_CHECK' + ); + }); + + it("fails if asset is not a CToken", async () => { + const comptroller = await makeComptroller() + const asset = await makeToken(root); + await assert.revert(send(comptroller, '_supportMarket', [asset._address])); + }); + + it("succeeds and sets market", async () => { + const cToken = await makeCToken(); + const result = await send(cToken.comptroller, '_supportMarket', [cToken._address]); + assert.hasLog(result, 'MarketListed', {cToken: cToken._address}); + }); + + it("cannot list a market a second time", async () => { + const cToken = await makeCToken(); + const result1 = await send(cToken.comptroller, '_supportMarket', [cToken._address]); + const result2 = await send(cToken.comptroller, '_supportMarket', [cToken._address]); + assert.hasLog(result1, 'MarketListed', {cToken: cToken._address}); + assert.hasTrollFailure( + result2, + 'MARKET_ALREADY_LISTED', + 'SUPPORT_MARKET_EXISTS' + ); + }); + + it("can list two different markets", async () => { + const cToken1 = await makeCToken(); + const cToken2 = await makeCToken({comptroller: cToken1.comptroller}); + const result1 = await send(cToken1.comptroller, '_supportMarket', [cToken1._address]); + const result2 = await send(cToken1.comptroller, '_supportMarket', [cToken2._address]); + assert.hasLog(result1, 'MarketListed', {cToken: cToken1._address}); + assert.hasLog(result2, 'MarketListed', {cToken: cToken2._address}); + }); + }); + + describe('redeemVerify', async () => { + it('should allow you to redeem 0 underlying for 0 tokens', async () => { + const comptroller = await makeComptroller(); + const cToken = await makeCToken({comptroller: comptroller}); + await call(comptroller, 'redeemVerify', [cToken._address, accounts[0], 0, 0]); + }); + + it('should allow you to redeem 5 underlyig for 5 tokens', async () => { + const comptroller = await makeComptroller(); + const cToken = await makeCToken({comptroller: comptroller}); + await call(comptroller, 'redeemVerify', [cToken._address, accounts[0], 5, 5]); + }); + + it('should not allow you to redeem 5 underlying for 0 tokens', async () => { + const comptroller = await makeComptroller(); + const cToken = await makeCToken({comptroller: comptroller}); + await assert.revert(call(comptroller, 'redeemVerify', [cToken._address, accounts[0], 5, 0]), "revert redeemTokens zero"); + }); + }) +}); diff --git a/test/Comptroller/liquidateCalculateAmountSeizeTest.js b/test/Comptroller/liquidateCalculateAmountSeizeTest.js new file mode 100644 index 000000000..f8c5482fc --- /dev/null +++ b/test/Comptroller/liquidateCalculateAmountSeizeTest.js @@ -0,0 +1,97 @@ +const {etherUnsigned, call, send} = require('../Utils/MochaTruffle'); +const { + makeComptroller, + makeCToken, + setOraclePrice +} = require('../Utils/Compound'); + +const borrowedPrice = 2e10; +const collateralPrice = 1e18; +const repayAmount = etherUnsigned(1e18); + +async function calculateSeizeTokens(comptroller, cTokenBorrowed, cTokenCollateral, repayAmount) { + return call(comptroller, 'liquidateCalculateSeizeTokens', [cTokenBorrowed._address, cTokenCollateral._address, repayAmount]); +} + +function rando(min, max) { + return Math.floor(Math.random() * (max - min)) + min; +} + +contract('Comptroller', function([root, ...accounts]) { + let comptroller, cTokenBorrowed, cTokenCollateral; + before(async () => { + comptroller = await makeComptroller(); + cTokenBorrowed = await makeCToken({comptroller: comptroller, underlyingPrice: 0}); + cTokenCollateral = await makeCToken({comptroller: comptroller, underlyingPrice: 0}); + }); + + beforeEach(async () => { + await setOraclePrice(cTokenBorrowed, borrowedPrice); + await setOraclePrice(cTokenCollateral, collateralPrice); + await send(cTokenCollateral, 'harnessExchangeRateDetails', [8e10, 4e10, 0]); + }); + + describe('liquidateCalculateAmountSeize', async () => { + it("fails if either asset price is 0", async () => { + await setOraclePrice(cTokenBorrowed, 0); + assert.hasTrollErrorTuple( + await calculateSeizeTokens(comptroller, cTokenBorrowed, cTokenCollateral, repayAmount), + ['PRICE_ERROR', 0] + ); + + await setOraclePrice(cTokenCollateral, 0); + assert.hasTrollErrorTuple( + await calculateSeizeTokens(comptroller, cTokenBorrowed, cTokenCollateral, repayAmount), + ['PRICE_ERROR', 0] + ); + }); + + it("fails if the repayAmount causes overflow ", async () => { + assert.hasTrollErrorTuple( + await calculateSeizeTokens(comptroller, cTokenBorrowed, cTokenCollateral, -1), + ['MATH_ERROR', 0] + ); + }); + + it("fails if the borrowed asset price causes overflow ", async () => { + await setOraclePrice(cTokenBorrowed, -1); + assert.hasTrollErrorTuple( + await calculateSeizeTokens(comptroller, cTokenBorrowed, cTokenCollateral, repayAmount), + ['MATH_ERROR', 0] + ); + }); + + it("reverts if it fails to calculate the exchange rate", async () => { + await send(cTokenCollateral, 'harnessExchangeRateDetails', [1, 0, 10]); // (1 - 10) -> underflow + await assert.revert( + send(comptroller, 'liquidateCalculateSeizeTokens', [cTokenBorrowed._address, cTokenCollateral._address, repayAmount]), + "revert exchangeRateStored: exchangeRateStoredInternal failed" + ); + }); + + [ + [1e18, 1e18, 1e18, 1e18, 1e18], + [2e18, 1e18, 1e18, 1e18, 1e18], + [2e18, 2e18, 1.42e18, 1.3e18, 2.45e18], + [2.789e18, 5.230480842e18, 771.32e18, 1.3e18, 10002.45e18], + [ 7.009232529961056e+24,2.5278726317240445e+24,2.6177112093242585e+23,1179713989619784000,7.790468414639561e+24 ], + [rando(0, 1e25), rando(0, 1e25), rando(1, 1e25), rando(1e18, 1.5e18), rando(0, 1e25)] + ].forEach((testCase) => { + it(`returns the correct value for ${testCase}`, async () => { + const [exchangeRate, borrowedPrice, collateralPrice, liquidationIncentive, repayAmount] = testCase.map(etherUnsigned); + + await setOraclePrice(cTokenCollateral, collateralPrice); + await setOraclePrice(cTokenBorrowed, borrowedPrice); + await send(comptroller, '_setLiquidationIncentive', [liquidationIncentive]); + await send(cTokenCollateral, 'harnessSetExchangeRate', [exchangeRate]); + + const seizeAmount = repayAmount.mul(liquidationIncentive).mul(borrowedPrice).div(collateralPrice); + const seizeTokens = seizeAmount.div(exchangeRate); + assert.hasTrollErrorTuple( + await calculateSeizeTokens(comptroller, cTokenBorrowed, cTokenCollateral, repayAmount), + ['NO_ERROR', (x) => assert.approximately(Number(x), Number(seizeTokens), 1e7)] + ); + }); + }); + }); +}); diff --git a/test/Comptroller/proxiedComptrollerV1Test.js b/test/Comptroller/proxiedComptrollerV1Test.js new file mode 100644 index 000000000..74b6a4d6e --- /dev/null +++ b/test/Comptroller/proxiedComptrollerV1Test.js @@ -0,0 +1,192 @@ +const { + address, + etherMantissa, + getContract, + getTestContract, + call, + send +} = require('../Utils/MochaTruffle'); + +const { + makeComptroller, + makeCToken, + makePriceOracle +} = require('../Utils/Compound'); + +const Unitroller = getContract('Unitroller'); +const Comptroller = getContract('Comptroller'); + +contract('ComptrollerV1', function([root, ...accounts]) { + let unitroller; + let brains; + let oracle; + + before(async () => { + oracle = await makePriceOracle() + brains = await Comptroller.deploy().send({from: root}); + }); + + beforeEach(async () => { + unitroller = await Unitroller.deploy().send({from: root}); + }); + + let initializeBrains = async (priceOracle, closeFactor, maxAssets) => { + await send(unitroller, '_setPendingImplementation', [brains._address]); + await send(brains, '_become', [unitroller._address, priceOracle._address, closeFactor, maxAssets, false]); + return Comptroller.at(unitroller._address); + }; + + let reinitializeBrains = async () => { + await send(unitroller, '_setPendingImplementation', [brains._address]); + await send(brains, '_become', [unitroller._address, address(0), 0, 0, true]); + return Comptroller.at(unitroller._address); + }; + + describe("delegating to comptroller v1", async () => { + const closeFactor = etherMantissa(.051), maxAssets = 10; + + let unitrollerAsComptroller, cToken; + beforeEach( async () => { + unitrollerAsComptroller = await initializeBrains(oracle, etherMantissa(.06), 30); + cToken = await makeCToken({comptroller: unitrollerAsComptroller}); + }); + + describe("becoming brains sets initial state", async () => { + it("reverts if this is not the pending implementation", async () => { + await assert.revert(send(brains, '_become', [unitroller._address, oracle._address, 0, 10, false]), "revert change not authorized"); + }); + + it("on success it sets admin to caller of constructor", async () => { + assert.equal(await call(unitrollerAsComptroller, 'admin'), root); + assert.addressZero(await call(unitrollerAsComptroller, 'pendingAdmin'), "pendingAdmin should be zero for a new contract"); + }); + + it("on success it sets closeFactor and maxAssets as specified", async () => { + const comptroller = await initializeBrains(oracle, closeFactor, maxAssets); + assert.equal(await call(comptroller, 'closeFactorMantissa'), closeFactor, "closeFactor"); + assert.equal(await call(comptroller, 'maxAssets'), maxAssets, "maxAssets"); + }); + + it("on reinitialization success, it doesn't set closeFactor or maxAssets", async () => { + let comptroller = await initializeBrains(oracle, closeFactor, maxAssets); + assert.equal(await call(unitroller, 'comptrollerImplementation'), brains._address); + assert.equal(await call(comptroller, 'closeFactorMantissa',), closeFactor, "closeFactor"); + assert.equal(await call(comptroller, 'maxAssets'), maxAssets, "maxAssets"); + + // Create new brains + brains = await Comptroller.deploy().send({from: root}); + comptroller = await reinitializeBrains(); + + assert.equal(await call(unitroller, 'comptrollerImplementation'), brains._address); + assert.equal(await call(comptroller, 'closeFactorMantissa'), closeFactor, "closeFactor"); + assert.equal(await call(comptroller, 'maxAssets'), maxAssets, "maxAssets"); + }); + + it("reverts on invalid closeFactor", async () => { + await send(unitroller, '_setPendingImplementation', [brains._address]); + await assert.revert(send(brains, '_become', [unitroller._address, oracle._address, 0, maxAssets, false]), "revert set close factor error"); + }); + + it("allows 0 maxAssets", async () => { + const comptroller = await initializeBrains(oracle, closeFactor, 0); + assert.equal(await call(comptroller, 'maxAssets'), 0, "maxAssets"); + }); + + it("allows 5000 maxAssets", async () => { + // 5000 is an arbitrary number larger than what we expect to ever actually use + const comptroller = await initializeBrains(oracle, closeFactor, 5000); + assert.equal(await call(comptroller, 'maxAssets'), 5000, "maxAssets"); + }); + }); + + describe("_setCollateralFactor", async () => { + const half = etherMantissa(.5), one = etherMantissa(1); + + it("fails if not called by admin", async () => { + assert.hasTrollFailure( + await send(unitrollerAsComptroller, '_setCollateralFactor', [cToken._address, half], {from: accounts[1]}), + 'UNAUTHORIZED', + 'SET_COLLATERAL_FACTOR_OWNER_CHECK' + ); + }); + + it("fails if asset is not listed", async () => { + assert.hasTrollFailure( + await send(unitrollerAsComptroller, '_setCollateralFactor', [cToken._address, half]), + 'MARKET_NOT_LISTED', + 'SET_COLLATERAL_FACTOR_NO_EXISTS' + ); + }); + + it("fails if factor is too high", async () => { + const cToken = await makeCToken({supportMarket: true, comptroller: unitrollerAsComptroller}); + assert.hasTrollFailure( + await send(unitrollerAsComptroller, '_setCollateralFactor', [cToken._address, one]), + 'INVALID_COLLATERAL_FACTOR', + 'SET_COLLATERAL_FACTOR_VALIDATION' + ); + }); + + it("fails if factor is set without an underlying price", async () => { + const cToken = await makeCToken({supportMarket: true, comptroller: unitrollerAsComptroller}); + assert.hasTrollFailure( + await send(unitrollerAsComptroller, '_setCollateralFactor', [cToken._address, half]), + 'PRICE_ERROR', + 'SET_COLLATERAL_FACTOR_WITHOUT_PRICE' + ); + }); + + it("succeeds and sets market", async () => { + const cToken = await makeCToken({supportMarket: true, comptroller: unitrollerAsComptroller}); + await send(oracle, 'setUnderlyingPrice', [cToken._address, 1]); + assert.hasLog( + await send(unitrollerAsComptroller, '_setCollateralFactor', [cToken._address, half]), + 'NewCollateralFactor', { + cToken: cToken._address, + oldCollateralFactorMantissa: "0", + newCollateralFactorMantissa: half.toString() + }); + }); + }); + + describe("_supportMarket", async () => { + it("fails if not called by admin", async () => { + assert.hasTrollFailure( + await send(unitrollerAsComptroller, '_supportMarket', [cToken._address], {from: accounts[1]}), + 'UNAUTHORIZED', + 'SUPPORT_MARKET_OWNER_CHECK' + ); + }); + + it("fails if asset is not a CToken", async () => { + const notACToken = await makePriceOracle(); + await assert.revert(send(unitrollerAsComptroller, '_supportMarket', [notACToken._address])); + }); + + it("succeeds and sets market", async () => { + const result = await send(unitrollerAsComptroller, '_supportMarket', [cToken._address]); + assert.hasLog(result, 'MarketListed', {cToken: cToken._address}); + }); + + it("cannot list a market a second time", async () => { + const result1 = await send(unitrollerAsComptroller, '_supportMarket', [cToken._address]); + const result2 = await send(unitrollerAsComptroller, '_supportMarket', [cToken._address]); + assert.hasLog(result1, 'MarketListed', {cToken: cToken._address}); + assert.hasTrollFailure( + result2, + 'MARKET_ALREADY_LISTED', + 'SUPPORT_MARKET_EXISTS' + ); + }); + + it("can list two different markets", async () => { + const cToken1 = await makeCToken({comptroller: unitroller}); + const cToken2 = await makeCToken({comptroller: unitroller}); + const result1 = await send(unitrollerAsComptroller, '_supportMarket', [cToken1._address]); + const result2 = await send(unitrollerAsComptroller, '_supportMarket', [cToken2._address]); + assert.hasLog(result1, 'MarketListed', {cToken: cToken1._address}); + assert.hasLog(result2, 'MarketListed', {cToken: cToken2._address}); + }); + }); + }); +}); diff --git a/test/Comptroller/unitrollerTest.js b/test/Comptroller/unitrollerTest.js new file mode 100644 index 000000000..0eea6fa41 --- /dev/null +++ b/test/Comptroller/unitrollerTest.js @@ -0,0 +1,180 @@ +const { + address, + etherMantissa, + getContract, + getTestContract, + call, + send +} = require('../Utils/MochaTruffle'); + +const { + makeComptroller, + makePriceOracle +} = require('../Utils/Compound'); + +const Unitroller = getContract('Unitroller'); +const Comptroller = getContract('Comptroller'); +const EchoTypesComptroller = getTestContract('EchoTypesComptroller'); + +contract('Unitroller', function([root, ...accounts]) { + let unitroller; + let brains; + let oracle; + before(async () => { + oracle = await makePriceOracle() + brains = await Comptroller.deploy().send({from: root}); + }); + + beforeEach(async () => { + unitroller = await Unitroller.deploy().send({from: root}); + }); + + let setPending = (implementation, from) => { + return send(unitroller, '_setPendingImplementation', [implementation._address], {from}); + }; + + describe("constructor", async () => { + it("sets admin to caller and addresses to 0", async () => { + assert.equal(await call(unitroller, 'admin'), root); + assert.addressZero(await call(unitroller, 'pendingAdmin')); + assert.addressZero(await call(unitroller, 'pendingComptrollerImplementation')); + assert.addressZero(await call(unitroller, 'comptrollerImplementation')); + }); + }); + + describe("_setPendingImplementation", async () => { + describe("Check caller is admin", async () => { + let result; + before(async () => { + result = await setPending(brains, accounts[1]); + }); + + it("emits a failure log", async () => { + assert.hasTrollFailure( + result, + 'UNAUTHORIZED', + 'SET_PENDING_IMPLEMENTATION_OWNER_CHECK' + ); + }); + + it("does not change pending implementation address", async () => { + assert.addressZero(await call(unitroller, 'pendingComptrollerImplementation')) + }); + }); + + describe("succeeding", async () => { + it("stores pendingComptrollerImplementation with value newPendingImplementation", async () => { + await setPending(brains, root); + assert.equal(await call(unitroller, 'pendingComptrollerImplementation'), brains._address); + }); + + it("emits NewPendingImplementation event", async () => { + assert.hasLog( + await send(unitroller, '_setPendingImplementation', [brains._address]), + 'NewPendingImplementation', { + oldPendingImplementation: address(0), + newPendingImplementation: brains._address + }); + }); + }); + }); + + describe("_acceptImplementation", async () => { + describe("Check caller is pendingComptrollerImplementation and pendingComptrollerImplementation ≠ address(0) ", async () => { + let result; + beforeEach(async () => { + await setPending(unitroller, root); + result = await send(unitroller, '_acceptImplementation'); + }); + + it("emits a failure log", async () => { + assert.hasTrollFailure( + result, + 'UNAUTHORIZED', + 'ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK' + ); + }); + + it("does not change current implementation address", async () => { + assert.notEqual(await call(unitroller, 'comptrollerImplementation'), unitroller._address); + }); + }); + + it.skip("rejects if pending impl is address(0)", async () => { + // XXX TODO? + }); + + describe("the brains must accept the responsibility of implementation", async () => { + let result; + beforeEach(async () => { + await setPending(brains, root); + result = await send(brains, '_become', [unitroller._address, oracle._address, etherMantissa(.051), 10, false]); + assert.success(result); + }); + + it("Store comptrollerImplementation with value pendingComptrollerImplementation", async () => { + assert.equal(await call(unitroller, 'comptrollerImplementation'), brains._address); + }); + + it("Unset pendingComptrollerImplementation", async () => { + assert.addressZero(await call(unitroller, 'pendingComptrollerImplementation')); + }); + + it.skip("Emit NewImplementation(oldImplementation, newImplementation)", async () => { + // TODO: + // Does our log decoder expect it to come from the same contract? + // assert.hasLog( + // result, + // "NewImplementation", + // { + // newImplementation: brains._address, + // oldImplementation: "0x0000000000000000000000000000000000000000" + // }); + }); + + it.skip("Emit NewPendingImplementation(oldPendingImplementation, 0)", async () => { + // TODO: + // Does our log decoder expect it to come from the same contract? + // Having difficulty decoding these events + // assert.hasLog( + // result, + // "NewPendingImplementation", + // { + // oldPendingImplementation: brains._address, + // newPendingImplementation: "0x0000000000000000000000000000000000000000" + // }); + }); + }); + + describe("fallback delegates to brains", async () => { + let troll; + before(async () => { + troll = await EchoTypesComptroller.deploy().send({from: root}); + unitroller = await Unitroller.deploy().send({from: root}); + await setPending(troll, root); + await send(troll, 'becomeBrains', [unitroller._address]); + troll.options.address = unitroller._address; + }); + + it("forwards reverts", async () => { + await assert.revert(call(troll, 'reverty'), "revert gotcha sucka"); + }); + + it("gets addresses", async () => { + assert.equal(await call(troll, 'addresses', [troll._address]), troll._address); + }); + + it("gets strings", async () => { + assert.equal(await call(troll, 'stringy', ["yeet"]), "yeet"); + }); + + it("gets bools", async () => { + assert.equal(await call(troll, 'booly', [true]), true); + }); + + it("gets list of ints", async () => { + assert.deepEqual(await call(troll, 'listOInts', [[1,2,3]]), ["1", "2", "3"]); + }); + }); + }); +}); diff --git a/test/Errors.js b/test/Errors.js new file mode 100644 index 000000000..615fbfb99 --- /dev/null +++ b/test/Errors.js @@ -0,0 +1,50 @@ +"use strict"; + +/* + * This module loads Error and FailureInfo enum from ErrorReporter.sol. + */ + +const path = require('path'); +const solparse = require('solparse'); + +const errorReporterPath = path.join(__dirname, '..', 'contracts', 'ErrorReporter.sol'); +const contents = solparse.parseFile(errorReporterPath); +const [ + ComptrollerErrorReporter, + TokenErrorReporter +] = contents.body.filter(k => k.type === 'ContractStatement'); + +function invert(object) { + return Object.entries(object).reduce((obj, [key, value]) => ({ ...obj, [value]: key }), {}); +} + +function parse(reporter) { + const ErrorInv = reporter.body.find(k => k.name == 'Error').members; + const FailureInfoInv = reporter.body.find(k => k.name == 'FailureInfo').members; + const Error = invert(ErrorInv); + const FailureInfo = invert(FailureInfoInv); + return {Error, FailureInfo, ErrorInv, FailureInfoInv}; +} + +const carefulMathPath = path.join(__dirname, '..', 'contracts', 'CarefulMath.sol'); +const CarefulMath = solparse.parseFile(carefulMathPath).body.find(k => k.type === 'ContractStatement'); +const MathErrorInv = CarefulMath.body.find(k => k.name == 'MathError').members; +const MathError = invert(MathErrorInv); + +const whitePaperModelPath = path.join(__dirname, '..', 'contracts', 'WhitePaperInterestRateModel.sol'); +const whitePaperModel = solparse.parseFile(whitePaperModelPath).body.find(k => k.type === 'ContractStatement'); +const IRErrorInv = whitePaperModel.body.find(k => k.name == 'IRError').members; +const IRError = invert(IRErrorInv); + +module.exports = { + ComptrollerErr: parse(ComptrollerErrorReporter), + TokenErr: parse(TokenErrorReporter), + IRErr: { + Error: IRError, + ErrorInv: IRErrorInv + }, + MathErr: { + Error: MathError, + ErrorInv: MathErrorInv + } +}; diff --git a/test/ExponentialTest.sol b/test/ExponentialTest.sol new file mode 100644 index 000000000..65680566f --- /dev/null +++ b/test/ExponentialTest.sol @@ -0,0 +1,467 @@ +pragma solidity ^0.5.8; + +import "truffle/Assert.sol"; +import "../contracts/Exponential.sol"; + +contract ExponentialTest is Exponential { + + /** + * @dev helper that lets us create an Exp with `getExp` without cluttering our test code with error checks of the setup. + */ + function getExpFromRational(uint numerator, uint denominator) internal returns (Exp memory) { + (MathError err, Exp memory result) = getExp(numerator, denominator); + + Assert.equal(0, uint(err), "getExpFromRational failed"); + return result; + } + + function testGetExp_Simple() public { + (MathError err, Exp memory val) = getExp(50, 10000); // 50 basis points + + assertNoError(err); + Assert.equal(5000000000000000, val.mantissa, "should be 50 basis points"); + } + + function testGetExp_WithDenomOfOne() public { + (MathError err, Exp memory val) = getExp(5, 1); // The number 5.0 + + assertNoError(err); + Assert.equal(5000000000000000000, val.mantissa, "should be 5.0"); + } + + function testGetZero_Zero() public { + (MathError err, Exp memory val) = getExp(0, 10000); // 0 basis points + + assertNoError(err); + Assert.equal(0, val.mantissa, "should be 0 basis points"); + } + + function testGetExp_FailToGetDivByZero() public { + (MathError err, Exp memory val) = getExp(1, 0); + + assertError(MathError.DIVISION_BY_ZERO, err, "divide by zero"); + assertZero(val.mantissa, "default value"); + } + + function testGetExp_Overflow() public { + (MathError err, Exp memory val) = getExp(uint(-1), uint(-1)); // 1, but overflows + + assertError(MathError.INTEGER_OVERFLOW, err, "overflows max int"); + assertZero(val.mantissa, "default value"); + } + + function testAddExp_Successful() public { + (MathError err0, Exp memory val1) = getExp(50, 10000); // 50 basis points + assertNoError(err0); + + (MathError err1, Exp memory val2) = getExp(60, 10000); // 60 basis points + assertNoError(err1); + + (MathError err2, Exp memory sum) = addExp(val1, val2); + assertNoError(err2); + + Assert.equal(11000000000000000, sum.mantissa, "should be 110 basis points"); + } + + function testAddExp_Overflow() public { + Exp memory val1 = Exp({mantissa: uint(-1)}); + Exp memory val2 = Exp({mantissa: uint(-1)}); + + (MathError err, Exp memory sum) = addExp(val1, val2); + + assertError(MathError.INTEGER_OVERFLOW, err, "overflowed with addition"); + assertZero(sum.mantissa, "default value"); + } + + function testSubExp_Successful() public { + (MathError err0, Exp memory val1) = getExp(50, 10000); // 50 basis points + assertNoError(err0); + + (MathError err1, Exp memory val2) = getExp(60, 10000); // 60 basis points + assertNoError(err1); + + (MathError err2, Exp memory difference) = subExp(val2, val1); + assertNoError(err2); + + Assert.equal(1000000000000000, difference.mantissa, "should be 10 basis points"); + + // -1 - (-1) should actually work out to 0 + (MathError err3, Exp memory difference2) = subExp(Exp({mantissa: uint(-1)}), Exp({mantissa: uint(-1)})); + assertNoError(err3); + + Assert.equal(0, difference2.mantissa, "should be 0 basis points"); + } + + function testSubExp_Underflow() public { + (MathError err0, Exp memory val1) = getExp(5, 1); + assertNoError(err0); + + (MathError err1, Exp memory val2) = getExp(7, 1); + assertNoError(err1); + + (MathError err2, Exp memory difference) = subExp(val1, val2); // 5 - 7 = underflow + + assertError(MathError.INTEGER_UNDERFLOW, err2, "underflowed with subtraction"); + assertZero(difference.mantissa, "default value"); + } + + function testMulExp_Successful() public { + + (MathError err0, Exp memory val1) = getExp(50, 100); // 1/2 + assertNoError(err0); + + (MathError err1, Exp memory val2) = getExp(202, 100); // 2.02 + assertNoError(err1); + + (MathError err2, Exp memory product) = mulExp(val1, val2); + + assertNoError(err2); + Assert.equal(1010000000000000000, product.mantissa, "product should be 1.01"); + } + + function testMulExp3_Successful() public { + (MathError err0, Exp memory val1) = getExp(1, 2); + assertNoError(err0); + + (MathError err1, Exp memory val2) = getExp(1, 3); + assertNoError(err1); + + (MathError err2, Exp memory val3) = getExp(1, 5); + assertNoError(err2); + + (MathError err3, Exp memory product) = mulExp3(val1, val2, val3); + assertNoError(err3); + Assert.equal(33333333333333333, product.mantissa, "product should be 1/30"); + } + + function testMulExp3_Small() public { + (MathError err0, Exp memory val1) = getExp(1, 2); + assertNoError(err0); + + (MathError err1, Exp memory val2) = getExp(1, 1e18); + assertNoError(err1); + + (MathError err2, Exp memory val3) = getExp(1, 1); + assertNoError(err2); + + (MathError err3, Exp memory product) = mulExp3(val1, val2, val3); + assertNoError(err3); + Assert.equal(1, product.mantissa, "product should be 5e-19, rounded to 1e-18"); + } + + // This fails without the addition of the half scale before descaling the intermediate value + function testMulExp_RoundAtFarRight() public { + + (MathError err0, Exp memory val1) = getExp(2, 3); // 2/3 + assertNoError(err0); + + (MathError err1, Exp memory val2) = getExp(1, 10**18); // 1x10e-18 + assertNoError(err1); + + (MathError err2, Exp memory product) = mulExp(val1, val2); + + assertNoError(err2); // 2/3 * 1x10e-18 = 6.6... x 10e-19 + Assert.equal(1, product.mantissa, "product should be 6.666E-19, rounded to 1e-18"); + } + + function testMulExp_ZeroLeft() public { + + (MathError err0, Exp memory left) = getExp(0, 100); // 0 + assertNoError(err0); + + (MathError err1, Exp memory right) = getExp(202, 100); // 2.02 + assertNoError(err1); + + (MathError err2, Exp memory product) = mulExp(left, right); + + assertNoError(err2); + Assert.equal(0, product.mantissa, "product should be 0"); + } + + function testMulExp_ZeroRight() public { + + (MathError err0, Exp memory right) = getExp(0, 100); // 0 + assertNoError(err0); + + (MathError err1, Exp memory left) = getExp(202, 100); // 2.02 + assertNoError(err1); + + (MathError err2, Exp memory product) = mulExp(left, right); + + assertNoError(err2); + Assert.equal(0, product.mantissa, "product should be 0"); + } + + function testMulExp_OneLeft() public { + + (MathError err0, Exp memory left) = getExp(1, 1); // 1 + assertNoError(err0); + + (MathError err1, Exp memory right) = getExp(202, 100); // 2.02 + assertNoError(err1); + + (MathError err2, Exp memory product) = mulExp(left, right); + + assertNoError(err2); + Assert.equal(2020000000000000000, product.mantissa, "product should be 2.02"); + } + + function testMulExp_OneRight() public { + + (MathError err0, Exp memory right) = getExp(1, 1); // 1 + assertNoError(err0); + + (MathError err1, Exp memory left) = getExp(202, 100); // 2.02 + assertNoError(err1); + + (MathError err2, Exp memory product) = mulExp(left, right); + + assertNoError(err2); + Assert.equal(2020000000000000000, product.mantissa, "product should be 2.02"); + } + + function testMulExp_Overflow() public { + Exp memory val1 = Exp({mantissa: uint(-1)}); + Exp memory val2 = Exp({mantissa: uint(-1)}); + + (MathError err, Exp memory product) = mulExp(val1, val2); + + assertError(MathError.INTEGER_OVERFLOW, err, "overflowed with multiplication"); + assertZero(product.mantissa, "default value"); + } + + function testMulExp_OverflowOnAddHalfScale() public { + Exp memory bigger = Exp({mantissa: (2**256) - 1}); + Exp memory smaller = Exp({mantissa: 1}); + + MathError err; + Exp memory product; + + (err, product) = mulExp(bigger, smaller); + assertError(MathError.INTEGER_OVERFLOW, err, "should have returned MathError.INTEGER_OVERFLOW"); + + Assert.equal(0, product.mantissa, "product should be zero"); + } + + function testMulScalar_Big() public { + Exp memory val = getExpFromRational(10**58, 1); // Exp({mantissa: 10**76}); // our scaled representation of 10e59 + + Assert.equal(10**76, val.mantissa, "setup failed val.mantissa not 10e76"); + + (MathError err0, Exp memory scaled1) = mulScalar(val, 5); + assertNoError(err0); + Assert.equal(uint(5 * 10**76), scaled1.mantissa, "scalar multiplication failed- scaled1.mantissa not 50e76"); + + (MathError err1, Exp memory scaled2) = mulScalar(val, 100); + assertError(MathError.INTEGER_OVERFLOW, err1, "should have overflowed with scalar multiplication"); + Assert.equal(0, scaled2.mantissa, "should have overflowed"); + } + + function testMulScalar_Small() public { + Exp memory val = getExpFromRational(1, 10**16); // our scaled representation of 10e-16. + + Assert.equal(100, val.mantissa, "setup failed val2.mantissa not 100"); + + (MathError err0, Exp memory scaled) = mulScalar(val, 5); + assertNoError(err0); + Assert.equal(500, scaled.mantissa, "scalar multiplication failed- scaled2.mantissa not 500"); + } + + function testDivScalar_Big() public { + Exp memory val = getExpFromRational(10**58, 1); // Exp({mantissa: 10**76}); // our scaled representation of 10e59 + + Assert.equal(10**76, val.mantissa, "setup failed val.mantissa not 10e76"); + + (MathError err0, Exp memory scaled1) = divScalar(val, 5); + assertNoError(err0); + Assert.equal(uint(2 * 10**75), scaled1.mantissa, "scalar division failed- scaled1.mantissa not 2e76"); + + (MathError err1, Exp memory scaled2) = divScalar(val, 0); + assertError(MathError.DIVISION_BY_ZERO, err1, "should have caused division by zero"); + Assert.equal(0, scaled2.mantissa, "should be nilish"); + } + + function testDivScalar_Small() public { + Exp memory val = getExpFromRational(1, 10**16); // our scaled representation of 10e-16. + + Assert.equal(100, val.mantissa, "setup failed val.mantissa not 100"); + + (MathError err0, Exp memory scaled) = divScalar(val, 5); + assertNoError(err0); + Assert.equal(20, scaled.mantissa, "scalar division failed- scaled.mantissa not 20"); + } + + function testTruncate() public { + Assert.equal(10**58, truncate(getExpFromRational(10**58, 1)), "should truncate to 10**58"); + Assert.equal(0, truncate(getExpFromRational(1, 2)), "should truncate to 0"); + Assert.equal(0, truncate(getExpFromRational(2, 3)), "should truncate to 0"); + Assert.equal(1, truncate(getExpFromRational(3, 2)), "should truncate to 1"); + Assert.equal(8, truncate(getExpFromRational(4000, 500)), "should truncate to 8"); + Assert.equal(10**5, truncate(getExpFromRational(10**20, 10**15)), "should truncate to 2000"); + } + + function testIsZeroExp() public { + + Assert.equal(true, isZeroExp(getExpFromRational(0, 1)), "zero should be zero"); + Assert.equal(true, isZeroExp(getExpFromRational(0, 10**58)), "zero from a large denominator should be zero"); + + Assert.equal(false, isZeroExp(getExpFromRational(10**58, 3)), "large rational should not be zero"); + Assert.equal(false, isZeroExp(getExpFromRational(10**58, 1)), "large integer should not be zero"); + Assert.equal(false, isZeroExp(getExpFromRational(1, 1)), "small integer should not be zero"); + + Exp memory tinyFraction = getExpFromRational(1, 10**18); + Assert.equal(1, tinyFraction.mantissa, "tinyFraction setup failed"); + + Assert.equal(false, isZeroExp(tinyFraction), "tiny fraction should not be zero"); + } + + // divExp just calls getExp, which is already tested, so here we just verify that it is passing the + // correct arguments to getExp and check identities and error case + function testDivExp() public { + MathError err; + Exp memory result; + + //////////////////// + // Simple division + Exp memory left = getExpFromRational(1, 1); + Exp memory right = getExpFromRational(3, 1); + (err, result)= divExp(left, right); + assertNoError(err); + + Assert.equal(result.mantissa, 333333333333333333, "Exp division failed- result.mantissa not 333333333333333333"); + + //////////////////// + // Divide by 1 + left = getExpFromRational(3, 1); + right = getExpFromRational(1, 1); + (err, result)= divExp(left, right); + assertNoError(err); + + Assert.equal(result.mantissa, left.mantissa, "Exp division by 1 failed- result.mantissa not left.mantissa"); + + //////////////////// + // Divide very small number by itself + left = getExpFromRational(1, 10**16); // our scaled representation of 10e-16. + + (err, result) = divExp(left, left); + assertNoError(err); + + Assert.equal(result.mantissa, 1000000000000000000, "Exp division failed- result.mantissa not 1000000000000000000"); + + //////////////////// + // Divide by 0 returns error + left = getExpFromRational(1, 1000); // .001 + right = getExpFromRational(0, 1); // 0 + + (err, result) = divExp(left, right); + Assert.equal(uint(err), uint(MathError.DIVISION_BY_ZERO), "Exp division by 0 should have returned MathError.DIVISION_BY_ZERO"); + Assert.equal(result.mantissa, 0, "Exp division by 0 mantissa should be 0"); + } + + + function testDivScalarByExp() public { + MathError err; + Exp memory result; + + //////////////////// + // divide by 1 + (err, result) = divScalarByExp(300, getExpFromRational(1, 1)); + assertNoError(err); + + Assert.equal(result.mantissa, 300 * 10**18, "Exp division failed- result.mantissa not 300 * 10**18"); + + //////////////////// + // divide 0 by non-zero + (err, result) = divScalarByExp(0, getExpFromRational(108, 1000)); + assertNoError(err); + + Assert.equal(result.mantissa, 0, "Exp division failed- result.mantissa not 0"); + + //////////////////// + // simple division by rational > 1: 300 / 1.6 = 187.5 + (err, result) = divScalarByExp(300, getExpFromRational(16, 10)); + assertNoError(err); + + Assert.equal(result.mantissa, 187500000000000000000, "Exp division failed- result.mantissa not 187500000000000000000"); + + //////////////////// + // simple division by rational < 1: 300 / .85 = 352.9411764705882352941176470588235294117647058823529411764... + // scaled as 352941176470588235294 + (err, result) = divScalarByExp(300, getExpFromRational(85, 100)); + assertNoError(err); + + Assert.equal(result.mantissa, 352941176470588235294, "Exp division failed- result.mantissa not 352941176470588235294"); + + //////////////////// + // divide large uint by rational 123456789012 / 1.6 = 77160493132.5; scaled as 77160493132500000000000000000 + (err, result) = divScalarByExp(123456789012, getExpFromRational(16, 10)); + assertNoError(err); + + Assert.equal(result.mantissa, 77160493132500000000000000000, "Exp division failed- result.mantissa not 77160493132500000000000000000"); + + //////////////////// + // divide large uint by large rational + // 123456789012 / 987654321012345.7 = 0.000124999998871524997371961899045794758369664776317619765..., + // scaled as 124999998871525 + (err, result) = divScalarByExp(123456789012, getExpFromRational(9876543210123456, 10)); + assertNoError(err); + + Assert.equal(result.mantissa, 124999998871525, "Exp division failed- result.mantissa not 124999998871525"); + + //////////////////// + // overflow with large scalar > max Exp 2^237 - 1 + (err, result) = divScalarByExp(2**237, getExpFromRational(10, 1)); + + Assert.equal(uint(err), uint(MathError.INTEGER_OVERFLOW), "scalar >= 2**237 should cause overflow when converted to Exp"); + + //////////////////// + // division by zero + (err, result) = divScalarByExp(10, getExpFromRational(0, 1)); + + Assert.equal(uint(err), uint(MathError.DIVISION_BY_ZERO), "division by zero should return error DIVISION_BY_ZERO"); + } + + + function testLessThanOrEqualExp() public { + + // identity + Assert.isTrue(lessThanOrEqualExp(getExpFromRational(1, 1), getExpFromRational(1, 1)), "1/1 <= itself"); + Assert.isTrue(lessThanOrEqualExp(getExpFromRational(1, 3), getExpFromRational(1, 3)), "1/3 <= itself"); + Assert.isTrue(lessThanOrEqualExp(getExpFromRational(3, 1), getExpFromRational(3, 1)), "3/1 <= itself"); + Assert.isTrue(lessThanOrEqualExp(getExpFromRational(0, 1), getExpFromRational(0, 3)), "0 <= itself even with different demoninators"); + Assert.isTrue(lessThanOrEqualExp(getExpFromRational(11 * 10**17, 3), getExpFromRational(110 * 10**16, 3)), "(11 * 10**17)/3 <= itself"); + + // strictly less than + Assert.isTrue(lessThanOrEqualExp(getExpFromRational(7, 9), getExpFromRational(1, 1)), "7/9 <= 1"); + Assert.isTrue(lessThanOrEqualExp(getExpFromRational(1, 4), getExpFromRational(1, 3)), "1/4 <= 1/3"); + Assert.isTrue(lessThanOrEqualExp(getExpFromRational(3, 2), getExpFromRational(3, 1)), "3/2 <= 3 "); + Assert.isTrue(lessThanOrEqualExp(getExpFromRational(100, 3), getExpFromRational(100, 2)), "100/3 <= 100/2"); + Assert.isTrue(lessThanOrEqualExp(getExpFromRational(10**18, 3), getExpFromRational(10**19, 3)), "10e18/3 <= 10e19/3"); + + // Reverse the previous block of strictly less than tests + Assert.isFalse(lessThanOrEqualExp(getExpFromRational(1, 1), getExpFromRational(7, 9)), "1 !<= 7/9 "); + Assert.isFalse(lessThanOrEqualExp(getExpFromRational(1, 3), getExpFromRational(1, 4)), "1/3 !<= 1/4"); + Assert.isFalse(lessThanOrEqualExp(getExpFromRational(3, 1), getExpFromRational(3, 2)), "3 !<= 3/2"); + Assert.isFalse(lessThanOrEqualExp(getExpFromRational(100, 2), getExpFromRational(100, 3)), "100/2 !<= 100/3"); + Assert.isFalse(lessThanOrEqualExp(getExpFromRational(10**19, 3), getExpFromRational(10**18, 3)), "10e19/3 !<= 10e18/3"); + + // Let's do some more failure cases + Assert.isFalse(lessThanOrEqualExp(getExpFromRational(3, 1), getExpFromRational(1, 3)), "3/1 and 1/3"); + Assert.isFalse(lessThanOrEqualExp(getExpFromRational(3, 1), getExpFromRational(1, 1)), "3/1 and 1/1"); + Assert.isFalse(lessThanOrEqualExp(getExpFromRational(3, 1), getExpFromRational(0, 1)), "3/1 and 0/1"); + Assert.isFalse(lessThanOrEqualExp(getExpFromRational(30, 1), getExpFromRational(3, 1)), "30/1 and 3/1"); + } + + function assertError(MathError expected, MathError given, string memory message) internal { + Assert.equal(uint(expected), uint(given), message); + } + + function assertNoError(MathError err) internal { + assertError(MathError.NO_ERROR, err, "should have error NO_ERROR"); + } + + function assertZero(uint value, string memory message) internal { + Assert.equal(0, value, message); + } + +} \ No newline at end of file diff --git a/test/MaximillionTest.js b/test/MaximillionTest.js new file mode 100644 index 000000000..b9e8cac09 --- /dev/null +++ b/test/MaximillionTest.js @@ -0,0 +1,66 @@ +const { + etherBalance, + etherGasCost, + getContract, + call, + send +} = require('./Utils/MochaTruffle'); + +const { + makeComptroller, + makeCToken, + makePriceOracle, + pretendBorrow, + borrowSnapshot +} = require('./Utils/Compound'); + +const Maximillion = getContract('Maximillion'); + +contract('Maximillion', function([root, borrower]) { + let maximillion, cEther; + before(async () =>{ + cEther = await makeCToken({kind: "cether", supportMarket: true}); + maximillion = await Maximillion.deploy({arguments: [cEther._address]}).send({from: root}); + }); + + describe("constructor", async () => { + it("sets address of cEther", async () => { + assert.equal(await call(maximillion, "cEther"), cEther._address); + }); + }); + + describe("repayBehalf", async () => { + it("refunds the entire amount with no borrows", async () => { + const beforeBalance = await etherBalance(root); + const result = await send(maximillion, "repayBehalf", [borrower], {value: 100}); + const gasCost = await etherGasCost(result); + const afterBalance = await etherBalance(root); + assert.success(result); + assert.numEqual(afterBalance, beforeBalance.sub(gasCost)); + }); + + it("repays part of a borrow", async () => { + await pretendBorrow(cEther, borrower, 1, 1, 150); + const beforeBalance = await etherBalance(root); + const result = await send(maximillion, "repayBehalf", [borrower], {value: 100}); + const gasCost = await etherGasCost(result); + const afterBalance = await etherBalance(root); + const afterBorrowSnap = await borrowSnapshot(cEther, borrower); + assert.success(result); + assert.numEqual(afterBalance, beforeBalance.sub(gasCost).sub(100)); + assert.numEqual(afterBorrowSnap.principal, 50); + }); + + it("repays a full borrow and refunds the rest", async () => { + await pretendBorrow(cEther, borrower, 1, 1, 90); + const beforeBalance = await etherBalance(root); + const result = await send(maximillion, "repayBehalf", [borrower], {value: 100}); + const gasCost = await etherGasCost(result); + const afterBalance = await etherBalance(root); + const afterBorrowSnap = await borrowSnapshot(cEther, borrower); + assert.success(result); + assert.numEqual(afterBalance, beforeBalance.sub(gasCost).sub(90)); + assert.numEqual(afterBorrowSnap.principal, 0); + }); + }); +}); diff --git a/test/Models/interestRateModelTest.js b/test/Models/interestRateModelTest.js new file mode 100644 index 000000000..58a701bf6 --- /dev/null +++ b/test/Models/interestRateModelTest.js @@ -0,0 +1,150 @@ +const {call} = require('../Utils/MochaTruffle'); +const { + makeInterestRateModel, + getBorrowRate +} = require('../Utils/Compound'); + + +function utilizationRate(cash, borrows, reserves) { + return borrows ? borrows / (cash + borrows) : 0; +} + +function whitePaperRateFn(base, slope) { + return (cash, borrows, reserves) => { + const ua = utilizationRate(cash, borrows, reserves); + return (ua * slope + base) / blocksPerYear; + } +} + +const ExpectedRates = { + 'baseP025-slopeP20': {base: 0.025, slope: 0.20}, + 'baseP05-slopeP45': {base: 0.05, slope: 0.45}, + 'white-paper': {base: 0.1, slope: 0.45} +} + +const blocksPerYear = 2102400; +const rateInputs = [ + [500, 100], + [3e18, 5e18], + [5e18, 3e18], + [500, 3e18], + [0, 500], + [500, 0], + [0, 0], + [3e18, 500], + ["1000.00000000e18", "310.00000000e18"], + ["690.00000000e18", "310.00000000e18"] +].map(vs => vs.map(Number)); + +contract('InterestRateModel', async function ([root, ...accounts]) { + Object.entries(ExpectedRates).forEach(async ([kind, info]) => { + let model; + before(async () => { + model = await makeInterestRateModel({kind: 'white-paper', baseRate: info.base, multiplier: info.slope}); + }); + + const rateCases = (rateFn) => { + rateInputs.forEach(([cash, borrows, reserves = 0]) => { + it(`calculates correct borrow value for ${cash}, ${borrows}, ${reserves}`, async () => { + const expected = rateFn(cash, borrows, reserves); + assert.hasIRErrorTuple( + await getBorrowRate(model, cash, borrows, reserves), + ['NO_ERROR', (x) => assert.approximately(Number(x) / 1e18, expected, 1e7)] + ); + }); + }); + }; + + describe(kind, async () => { + it('isInterestRateModel', async () => { + assert.equal(await call(model, 'isInterestRateModel'), true); + }); + + rateCases(whitePaperRateFn(info.base, info.slope)); + + if (kind == 'white-paper') { + // Only need to do these for the WhitePaper + + it('handles overflowed cash + borrows', async () => { + assert.hasIRErrorTuple( + await getBorrowRate(model, -1, -1, 0), + ['FAILED_TO_ADD_CASH_PLUS_BORROWS', 0] + ); + }); + + it('handles failing to get exp of borrows / cash + borrows', async() => { + assert.hasIRErrorTuple( + await getBorrowRate(model, 0, -1, 0), + ['FAILED_TO_GET_EXP', 0] + ); + }); + + it('handles overflow utilization rate times slope', async() => { + const badModel = await makeInterestRateModel({kind, baseRate: 0, multiplier: -1}); + assert.hasIRErrorTuple( + await getBorrowRate(badModel, 1, 1, 0), + ['FAILED_TO_MUL_UTILIZATION_RATE', 0] + ); + }); + + it('handles overflow utilization rate times slope', async() => { + const badModel = await makeInterestRateModel({kind, baseRate: -1, multiplier: 1}); + assert.hasIRErrorTuple( + await getBorrowRate(badModel, 1, 1, 0), + ['FAILED_TO_ADD_BASE_RATE', 0] + ); + }); + + describe('getBorrowRate', async () => { + // We'll generate a large number of tests to verify approximate accuracy + [ + // Description of tests arrays: + // [base, slope, cash, borrows] + + // 50% base and 45% slope + [0.5e18, 0.45e18, 500, 100], + [0.5e18, 0.45e18, 3e18, 5e18], + [0.5e18, 0.45e18, 5e18, 3e18], + [0.5e18, 0.45e18, 500, 3e18], + [0.5e18, 0.45e18, 0, 500], + [0.5e18, 0.45e18, 500, 0], + [0.5e18, 0.45e18, 0, 0], + [0.5e18, 0.45e18, 3e18, 500], + [0.5e18, 0.45e18, "1000.00000000e18", "310.00000000e18"], + [0.5e18, 0.45e18, "690.00000000e18", "310.00000000e18"], + + // 10% base and 200% slope + [0.1e18, 2.0e18, 500, 100], + [0.1e18, 2.0e18, 3e18, 5e18], + [0.1e18, 2.0e18, 5e18, 3e18], + [0.1e18, 2.0e18, 500, 3e18], + [0.1e18, 2.0e18, 0, 500], + [0.1e18, 2.0e18, 500, 0], + [0.1e18, 2.0e18, 0, 0], + [0.1e18, 2.0e18, 3e18, 500], + + // 2000% base and 4000% slope + [20.0e18, 40.0e18, 500, 100], + [20.0e18, 40.0e18, 3e18, 5e18], + [20.0e18, 40.0e18, 5e18, 3e18], + [20.0e18, 40.0e18, 500, 3e18], + [20.0e18, 40.0e18, 0, 500], + [20.0e18, 40.0e18, 500, 0], + [20.0e18, 40.0e18, 0, 0], + [20.0e18, 40.0e18, 3e18, 500], + ].map(vs => vs.map(Number)) + .forEach(([base, slope, cash, borrows, reserves = 0]) => { // XXX add reserves + it(`calculates correct borrow value for base=${base/1e16}%,slope=${slope/1e16}%, cash=${cash}, borrows=${borrows}`, async () => { + const altModel = await makeInterestRateModel({kind: 'white-paper', baseRate: base / 1e18, multiplier: slope / 1e18}); + const expected = whitePaperRateFn(base / 1e18, slope / 1e18)(cash, borrows, reserves); + assert.hasIRErrorTuple( + await getBorrowRate(altModel, cash, borrows, reserves), + ['NO_ERROR', (x) => assert.approximately(Number(x) / 1e18, expected, 1e-8)] + ); + }); + }); + }); + } + }); + }) +}); \ No newline at end of file diff --git a/test/PriceOracleProxyTest.js b/test/PriceOracleProxyTest.js new file mode 100644 index 000000000..80efc806d --- /dev/null +++ b/test/PriceOracleProxyTest.js @@ -0,0 +1,129 @@ +const BigNumber = require('bignumber.js'); + +const { + address, + etherMantissa, + getContract, + call, + send +} = require('./Utils/MochaTruffle'); + +const { + makeComptroller, + makeCToken, + makePriceOracle, +} = require('./Utils/Compound'); + +const OraclePriceOracleProxy = getContract('PriceOracleProxy'); + +contract('PriceOracleProxy', function([root, ...accounts]) { + let oracle, comptroller, backingOracle, cEther, cErc20, cUsdc, fakeUSDC; + + before(async () =>{ + cEther = await makeCToken({kind: "cether", + comptrollerOpts: { kind: "v1-no-proxy"}, + supportMarket: true}); + + cUsdc = await makeCToken({comptroller: cEther.comptroller, + supportMarket: true}); + + backingOracle = await makePriceOracle(); + oracle = await OraclePriceOracleProxy + .deploy({ + arguments: [ + cEther.comptroller._address, + backingOracle._address, + cEther._address, + cUsdc._address + ]}) + .send({from: root}); + }); + + describe("constructor", async () => { + it("sets address of comptroller", async () => { + let configuredComptroller = await call(oracle, "comptroller"); + assert.equal(configuredComptroller, cEther.comptroller._address); + }); + + it("sets address of v1 oracle", async () => { + let configuredOracle = await call(oracle, "v1PriceOracle"); + assert.equal(configuredOracle, backingOracle._address); + }); + + it("sets address of cEther", async () => { + let configuredCEther = await call(oracle, "cEtherAddress"); + assert.equal(configuredCEther, cEther._address); + }); + + it("sets address of cUSDC", async () => { + let configuredCUSD = await call(oracle, "cUsdcAddress"); + assert.equal(configuredCUSD, cUsdc._address); + }); + }); + + describe("getUnderlyingPrice", async () => { + let setAndVerifyBackingPrice = async (cToken, price) => { + await send( + backingOracle, + "setUnderlyingPrice", + [cToken._address, etherMantissa(price)]); + + let backingOraclePrice = await call( + backingOracle, + "assetPrices", + [cToken.underlying._address]); + + assert.equal(Number(backingOraclePrice), price * 1e18); + }; + + let readAndVerifyProxyPrice = async (token, price) =>{ + let proxyPrice = await call(oracle, "getUnderlyingPrice", [token._address]); + assert.equal(Number(proxyPrice), price * 1e18);; + }; + + it("always returns 1e18 for cEther", async () => { + await readAndVerifyProxyPrice(cEther, 1); + }); + + it("checks address(1) for cusdc", async () => { + await send( + backingOracle, + "setDirectPrice", + [address(1), etherMantissa(50)]); + + await readAndVerifyProxyPrice(cUsdc, 50); + }); + + it("proxies to v1 oracle for listed cErc20's", async () => { + let listedToken = await makeCToken({comptroller: cEther.comptroller, supportMarket: true}); + + await setAndVerifyBackingPrice(listedToken, 12); + await readAndVerifyProxyPrice(listedToken, 12); + + await setAndVerifyBackingPrice(listedToken, 37); + await readAndVerifyProxyPrice(listedToken, 37); + }); + + describe("returns 0 for unlisted tokens", async () => { + it("right comptroller, not supported", async () => { + let unlistedToken = await makeCToken({comptroller: comptroller, + supportMarket: false}); + + await setAndVerifyBackingPrice(unlistedToken, 12); + await readAndVerifyProxyPrice(unlistedToken, 0); + }); + + it("wrong comptroller", async () => { + let wrongNetworkToken = await makeCToken({supportMarket: true}); + await setAndVerifyBackingPrice(wrongNetworkToken, 10); + + await readAndVerifyProxyPrice(wrongNetworkToken, 0); + }); + + it("not even a cToken", async () => { + let proxyPrice = await call(oracle, "getUnderlyingPrice", [root]); + assert.equal(Number(proxyPrice), 0); + }); + }); + }); +}); diff --git a/test/ScenarioTest.js b/test/ScenarioTest.js new file mode 100644 index 000000000..36e451350 --- /dev/null +++ b/test/ScenarioTest.js @@ -0,0 +1,121 @@ +"use strict"; + +const {initWorld, loadVerbose, loadInvokationOpts} = require('../scenario/.tsbuilt/World.js'); +const {processEvents} = require('../scenario/.tsbuilt/CoreEvent.js'); +const {parse} = require('../scenario/.tsbuilt/Parser.js'); +const {ConsolePrinter} = require('../scenario/.tsbuilt/Printer.js'); + +const fs = require('fs'); +const path = require('path'); + +const basePath = process.env.proj_root || path.join(process.cwd(), '..'); +const baseScenarioPath = path.join(basePath, 'spec', 'scenario'); +const coreMacros = fs.readFileSync(path.join(baseScenarioPath, 'CoreMacros')); + +const scenarios = {}; + +function loadScenarios(dir) { + fs.readdirSync(dir).forEach(file => { + const fullPath = `${dir}/${file}`; + + const stat = fs.statSync(fullPath); + + // Check if directory, and if so, recurse + if (stat && stat.isDirectory()) { + loadScenarios(fullPath); + } else { + // Ignore files if they don't match `.scen` + if (file.match(/\.scen$/)) { + // Load file data + const data = fs.readFileSync(fullPath, 'utf8'); + + // Get the name of the test from its file name + const name = file.replace(/\..*$/g, 'Scen'); + + try { + // Try and parse the file + const scen = parse(coreMacros + data); + + // Add each scenario, prefixed by test name + Object.entries(scen).forEach(([key, val]) => { + scenarios[`${name}: ${key}`] = val; + }); + } catch (e) { + throw `Cannot parse scenario ${file}: ${e}` + } + } + } + }); +} + +loadScenarios(baseScenarioPath); + +/** + * Allows user to specify a scenario filter + */ +let scenarioFilter; + +const scenarioEnv = process.env['scenarios'] || process.env['SCENARIOS']; +const verbose = !!process.env['verbose']; +const network = process.env['NETWORK'] || process.env['network'] || 'test'; + +if (scenarioEnv) { + console.log(`running scenarios matching: /${scenarioEnv}/i`); + scenarioFilter = new RegExp(scenarioEnv, 'i'); +} + +contract('ScenarioTest', function(accounts) { + /* + * This test runs our scenarios, which come from the reference implementation. + */ + + Object.entries(scenarios).forEach(([name, events]) => { + if (!scenarioFilter || name.match(scenarioFilter)) { + let fn = it; + let runner; + + switch (events[0]) { + case "Pending": + events = []; + break; + case "Gas": + // Skip gas tests on coverage + if (network === 'coverage') { + fn = it.skip; + } + events.shift(); + break; + case "Only": + fn = it.only; + events.shift(); + break; + case "Skip": + fn = it.skip; + events.shift(); + break; + } + + if (events.length === 0) { + runner = undefined; + } else { + runner = async () => { + let world = await initWorld(assert, new ConsolePrinter(verbose), web3, artifacts, network, accounts, basePath); + world = loadVerbose(world); + world = loadInvokationOpts(world); + + let finalWorld; + + // console.log(["Scenario", name, "Events", events, world]); + + finalWorld = await processEvents(world, events); + + // console.log(["Final world", finalWorld, finalWorld.actions]); + } + } + + fn("scenario: " + name, runner); + } else { + it.skip("scenario: " + name, async () => {}); + } + }); +}); diff --git a/test/SpinaramaTest.js b/test/SpinaramaTest.js new file mode 100644 index 000000000..119827ec1 --- /dev/null +++ b/test/SpinaramaTest.js @@ -0,0 +1,315 @@ +const { + etherMantissa, + minerStart, + minerStop, + send, + call +} = require('./Utils/MochaTruffle'); + +const { + makeCToken, + balanceOf, + borrowSnapshot, + enterMarkets +} = require('./Utils/Compound'); + +contract('Spinarama', function([root, from, ...accounts]) { + describe('#mintMint', async () => { + it('should succeed', async () => { + const cToken = await makeCToken({supportMarket: true}); + await send(cToken.underlying, 'harnessSetBalance', [from, 100], {from}); + await send(cToken.underlying, 'approve', [cToken._address, -1], {from}); + await minerStop(); + const p1 = send(cToken, 'mint', [1], {from}); + const p2 = send(cToken, 'mint', [2], {from}); + await minerStart(); + assert.success(await p1); + assert.success(await p2); + assert.numEqual(await balanceOf(cToken, from), 3); + }); + + it('should partial succeed', async () => { + const cToken = await makeCToken({supportMarket: true}); + await send(cToken.underlying, 'harnessSetBalance', [from, 100], {from}); + await send(cToken.underlying, 'approve', [cToken._address, 10], {from}); + await minerStop(); + const p1 = send(cToken, 'mint', [11], {from}); + const p2 = send(cToken, 'mint', [10], {from}); + await minerStart(); + assert.hasTokenFailure(await p1, 'TOKEN_INSUFFICIENT_ALLOWANCE', 'MINT_TRANSFER_IN_NOT_POSSIBLE'); + assert.success(await p2); + assert.numEqual(await balanceOf(cToken, from), 10); + }); + }); + + describe('#mintRedeem', async () => { + it('should succeed', async () => { + const cToken = await makeCToken({supportMarket: true}); + await send(cToken.underlying, 'harnessSetBalance', [from, 100], {from}); + await send(cToken.underlying, 'approve', [cToken._address, 10], {from}); + await minerStop(); + const p1 = send(cToken, 'mint', [10], {from}); + const p2 = send(cToken, 'redeemUnderlying', [10], {from}); + await minerStart(); + assert.success(await p1); + assert.success(await p2); + assert.numEqual(await balanceOf(cToken, from), 0); + }); + }); + + describe('#redeemMint', async () => { + it('should succeed', async () => { + const cToken = await makeCToken({supportMarket: true}); + await send(cToken, 'harnessSetTotalSupply', [10]); + await send(cToken, 'harnessSetExchangeRate', [etherMantissa(1)]); + await send(cToken, 'harnessSetBalance', [from, 10]); + await send(cToken.underlying, 'harnessSetBalance', [cToken._address, 10]); + await send(cToken.underlying, 'approve', [cToken._address, 10], {from}); + await minerStop(); + const p1 = send(cToken, 'redeem', [10], {from}); + const p2 = send(cToken, 'mint', [10], {from}); + await minerStart(); + assert.success(await p1); + assert.success(await p2); + assert.numEqual(await balanceOf(cToken, from), 10); + }); + }); + + describe('#repayRepay', async () => { + it('should succeed', async () => { + const cToken1 = await makeCToken({supportMarket: true, underlyingPrice: 1, collateralFactor: .5}); + const cToken2 = await makeCToken({supportMarket: true, underlyingPrice: 1, comptroller: cToken1.comptroller}); + await send(cToken1.underlying, 'harnessSetBalance', [from, 10]); + await send(cToken1.underlying, 'approve', [cToken1._address, 10], {from}); + await send(cToken2.underlying, 'harnessSetBalance', [cToken2._address, 10]); + await send(cToken2, 'harnessSetTotalSupply', [100]); + await send(cToken2.underlying, 'approve', [cToken2._address, 10], {from}); + await send(cToken2, 'harnessSetExchangeRate', [etherMantissa(1)]); + assert.success(await enterMarkets([cToken1, cToken2], from)); + assert.success(await send(cToken1, 'mint', [10], {from})); + assert.success(await send(cToken2, 'borrow', [2], {from})); + await minerStop(); + const p1 = send(cToken2, 'repayBorrow', [1], {from}); + const p2 = send(cToken2, 'repayBorrow', [1], {from}); + await minerStart(); + assert.success(await p1); + assert.success(await p2); + assert.numEqual((await borrowSnapshot(cToken2, from)).principal, 0); + }); + + // XXX not yet converted below this point...moving on to certora + + it.skip('can have partial failure succeed', async () => { + const {moneyMarketHarness, + priceOracle, + interestRateModel} = await setupMoneyMarket(root); + const spinarama = await Spinarama.new(moneyMarketHarness._address).send({from: root}); + const OMG = await setupSupply(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + const BAT = await setupBorrow(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + + // Add cash to the protocol + await addCash(moneyMarketHarness, BAT, root); + + // Supply some collateral + assert.success( + await spinarama.methods.supply(OMG._address, 15).send({from: accounts[0]})); + + // Now borrow 5 bat + assert.success( + await spinarama.methods.borrow(BAT._address, 5).send({from: accounts[0]})); + + // And repay it, repay it + const {'0': err0, '1': err1} = await spinarama.methods.repayRepay(BAT._address, 100, 1).call({from: accounts[0]}); + + assert.hasErrorCode(err0, ErrorEnum.INTEGER_UNDERFLOW); + assert.hasErrorCode(err1, ErrorEnum.NO_ERROR); + }); + }); + + describe('#borrowRepayBorrow', async () => { + it.skip('should fail', async () => { + const {moneyMarketHarness, + priceOracle, + interestRateModel} = await setupMoneyMarket(root); + const spinarama = await Spinarama.new(moneyMarketHarness._address).send({from: root}); + const OMG = await setupSupply(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + const BAT = await setupBorrow(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + + // Add cash to the protocol + await addCash(moneyMarketHarness, BAT, root); + + // Supply some collateral + assert.success( + await spinarama.methods.supply(OMG._address, 15).send({from: accounts[0]})); + + // Borrow then repayBorrow should revert + await assert.revert(spinarama.methods.borrowRepayBorrow(BAT._address, 5, 1).call({from: accounts[0]})); + }); + + it.skip('can succeed with partial failure', async () => { + const {moneyMarketHarness, + priceOracle, + interestRateModel} = await setupMoneyMarket(root); + const spinarama = await Spinarama.new(moneyMarketHarness._address).send({from: root}); + const OMG = await setupSupply(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + const BAT = await setupBorrow(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + + // Add cash to the protocol + await addCash(moneyMarketHarness, BAT, root); + + // Supply some collateral + assert.success( + await spinarama.methods.supply(OMG._address, 15).send({from: accounts[0]})); + + // Borrow a little, repay a lot + const {'0': err0, '1': err1} = await spinarama.methods.borrowRepayBorrow(BAT._address, 1, 1000).call({from: accounts[0]}); + + assert.hasErrorCode(err0, ErrorEnum.NO_ERROR); + assert.hasErrorCode(err1, ErrorEnum.INTEGER_UNDERFLOW); + }); + }); + + describe('#borrowSupply', async () => { + it.skip('should fail in same asset', async () => { + const {moneyMarketHarness, + priceOracle, + interestRateModel} = await setupMoneyMarket(root); + const spinarama = await Spinarama.new(moneyMarketHarness._address).send({from: root}); + const OMG = await setupSupply(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + const BAT = await setupBorrow(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + + // Add cash to the protocol + await addCash(moneyMarketHarness, BAT, root); + + // Supply some collateral + assert.success( + await spinarama.methods.supply(OMG._address, 15).send({from: accounts[0]})); + + // Borrow then supply should revert + await assert.revert(spinarama.methods.borrowSupply(BAT._address, BAT._address, 5, 1).call({from: accounts[0]})); + }); + + it.skip('should fail, even in different assets', async () => { + const {moneyMarketHarness, + priceOracle, + interestRateModel} = await setupMoneyMarket(root); + const spinarama = await Spinarama.new(moneyMarketHarness._address).send({from: root}); + const OMG = await setupSupply(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + const BAT = await setupBorrow(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + + // Add cash to the protocol + await addCash(moneyMarketHarness, BAT, root); + + // Supply some collateral + assert.success( + await spinarama.methods.supply(OMG._address, 15).send({from: accounts[0]})); + + // Borrow then supply in different assets + await assert.revert(spinarama.methods.borrowSupply(BAT._address, OMG._address, 5, 1).call({from: accounts[0]})); + }); + }); + + describe('#supplyLiquidate', async () => { + it.skip('should fail', async () => { + const {moneyMarketHarness, + priceOracle, + interestRateModel} = await setupMoneyMarket(root); + const spinarama = await Spinarama.new(moneyMarketHarness._address).send({from: root}); + const OMG = await setupSupply(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + const BAT = await setupBorrow(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + + // Add cash to the protocol + await addCash(moneyMarketHarness, BAT, root); + + // Supply some collateral + assert.success( + await spinarama.methods.supply(OMG._address, 15).send({from: accounts[0]})); + + await assert.revert(spinarama.methods.supplyLiquidate(OMG._address, 5, accounts[0], OMG._address, BAT._address, 0).call({from: accounts[0]})); + }); + }); + + describe('#withdrawLiquidate', async () => { + it.skip('should fail', async () => { + const {moneyMarketHarness, + priceOracle, + interestRateModel} = await setupMoneyMarket(root); + const spinarama = await Spinarama.new(moneyMarketHarness._address).send({from: root}); + const OMG = await setupSupply(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + const BAT = await setupBorrow(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + + // Add cash to the protocol + await addCash(moneyMarketHarness, BAT, root); + + // Supply some collateral + assert.success( + await spinarama.methods.supply(OMG._address, 15).send({from: accounts[0]})); + + await assert.revert(spinarama.methods.withdrawLiquidate(OMG._address, 5, accounts[0], OMG._address, BAT._address, 0).call({from: accounts[0]})); + }); + }); + + describe('#borrowLiquidate', async () => { + it.skip('should fail', async () => { + const {moneyMarketHarness, + priceOracle, + interestRateModel} = await setupMoneyMarket(root); + const spinarama = await Spinarama.new(moneyMarketHarness._address).send({from: root}); + const OMG = await setupSupply(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + const BAT = await setupBorrow(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + + // Add cash to the protocol + await addCash(moneyMarketHarness, BAT, root); + + // Supply some collateral + assert.success( + await spinarama.methods.supply(OMG._address, 15).send({from: accounts[0]})); + + await assert.revert(spinarama.methods.borrowLiquidate(OMG._address, 5, accounts[0], OMG._address, BAT._address, 0).call({from: accounts[0]})); + }); + }); + + describe('#repayBorrowLiquidate', async () => { + it.skip('should fail', async () => { + const {moneyMarketHarness, + priceOracle, + interestRateModel} = await setupMoneyMarket(root) + const spinarama = await Spinarama.new(moneyMarketHarness._address).send({from: root}); + const OMG = await setupSupply(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + const BAT = await setupBorrow(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + + // Add cash to the protocol + await addCash(moneyMarketHarness, BAT, root); + + // Supply some collateral + assert.success( + await spinarama.methods.supply(OMG._address, 15).send({from: accounts[0]})); + + // Borrow some OMG + assert.success( + await spinarama.methods.borrow(OMG._address, 5).send({from: accounts[0]})); + + await assert.revert(spinarama.methods.repayBorrowLiquidate(OMG._address, 1, accounts[0], OMG._address, BAT._address, 0).call({from: accounts[0]})); + }); + }); + + describe('#liquidateLiquidate', async () => { + it.skip('should fail', async () => { + const {moneyMarketHarness, + priceOracle, + interestRateModel} = await setupMoneyMarket(root) + const spinarama = await Spinarama.new(moneyMarketHarness._address).send({from: root}); + const OMG = await setupSupply(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + const BAT = await setupBorrow(root, accounts[0], spinarama, moneyMarketHarness, priceOracle, interestRateModel); + + // Add cash to the protocol + await addCash(moneyMarketHarness, BAT, root); + + // Supply some collateral + assert.success( + await spinarama.methods.supply(OMG._address, 15).send({from: accounts[0]})); + + await assert.revert(spinarama.methods.liquidateLiquidate(OMG._address, 1, accounts[0], OMG._address, BAT._address, 0).call({from: accounts[0]})); + }); + }); +}); diff --git a/test/Tokens/accrueInterestTest.js b/test/Tokens/accrueInterestTest.js new file mode 100644 index 000000000..cba5624b0 --- /dev/null +++ b/test/Tokens/accrueInterestTest.js @@ -0,0 +1,139 @@ +const {etherUnsigned, call, send} = require('../Utils/MochaTruffle'); +const { + makeCToken, + setBorrowRate +} = require('../Utils/Compound'); + +const blockNumber = 2e7; +const borrowIndex = 1e18; +const borrowRate = .0001; + +async function pretendBlock(cToken, accrualBlock = blockNumber, deltaBlocks = 1) { + await send(cToken, 'harnessSetAccrualBlockNumber', [etherUnsigned(blockNumber)]); + await send(cToken, 'harnessSetBlockNumber', [etherUnsigned(blockNumber + deltaBlocks)]); + await send(cToken, 'harnessSetBorrowIndex', [etherUnsigned(borrowIndex)]); +} + +async function preAccrue(cToken) { + await pretendBlock(cToken, blockNumber, 0); + await setBorrowRate(cToken, borrowRate); + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + await send(cToken, 'harnessExchangeRateDetails', [0, 0, 0]); +} + +contract('CToken', function ([root, ...accounts]) { + let cToken; + before(async () => { + cToken = await makeCToken({comptrollerOpts: {kind: 'bool'}}); + }); + + beforeEach(async () => { + await preAccrue(cToken); + }); + + describe('accrueInterest', async () => { + it('reverts if the interest rate is absurdly high', async () => { + await setBorrowRate(cToken, .001); + await assert.revert(send(cToken, 'accrueInterest'), "revert borrow rate is absurdly high"); + }); + + it('fails if new borrow rate calculation fails', async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + assert.hasTokenFailure( + await send(cToken, 'accrueInterest'), + 'INTEREST_RATE_MODEL_ERROR', + 'ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED' + ); + }); + + it('fails if simple interest factor calculation fails', async () => { + await pretendBlock(cToken, blockNumber, 5e70); + assert.hasTokenFailure( + await send(cToken, 'accrueInterest'), + 'MATH_ERROR', + 'ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED' + ); + }); + + it('fails if new borrow index calculation fails', async () => { + await pretendBlock(cToken, blockNumber, 5e60); + assert.hasTokenFailure( + await send(cToken, 'accrueInterest'), + 'MATH_ERROR', + 'ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED' + ); + }); + + it('fails if new borrow interest index calculation fails', async () => { + await pretendBlock(cToken) + await send(cToken, 'harnessSetBorrowIndex', [-1]); + assert.hasTokenFailure( + await send(cToken, 'accrueInterest'), + 'MATH_ERROR', + 'ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED' + ); + }); + + it('fails if interest accumulated calculation fails', async () => { + await send(cToken, 'harnessExchangeRateDetails', [0, -1, 0]); + await pretendBlock(cToken) + assert.hasTokenFailure( + await send(cToken, 'accrueInterest'), + 'MATH_ERROR', + 'ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED' + ); + }); + + it('fails if new total borrows calculation fails', async () => { + await setBorrowRate(cToken, 1e-18); + await pretendBlock(cToken) + await send(cToken, 'harnessExchangeRateDetails', [0, -1, 0]); + assert.hasTokenFailure( + await send(cToken, 'accrueInterest'), + 'MATH_ERROR', + 'ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED' + ); + }); + + it('fails if interest accumulated for reserves calculation fails', async () => { + await setBorrowRate(cToken, .0001); + await send(cToken, 'harnessExchangeRateDetails', [0, etherUnsigned(1e30), -1]); + await send(cToken, 'harnessSetReserveFactorFresh', [etherUnsigned(1e10)]); + await pretendBlock(cToken, blockNumber, 5e20) + assert.hasTokenFailure( + await send(cToken, 'accrueInterest'), + 'MATH_ERROR', + 'ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED' + ); + }); + + it('fails if new total reserves calculation fails', async () => { + await setBorrowRate(cToken, 1e-18); + await send(cToken, 'harnessExchangeRateDetails', [0, etherUnsigned(1e56), -1]); + await send(cToken, 'harnessSetReserveFactorFresh', [etherUnsigned(1e17)]); + await pretendBlock(cToken) + assert.hasTokenFailure( + await send(cToken, 'accrueInterest'), + 'MATH_ERROR', + 'ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED' + ); + }); + + it('succeeds and saves updated values in storage on success', async () => { + await send(cToken, 'harnessExchangeRateDetails', [0, etherUnsigned(1e22), etherUnsigned(1e20)]); + await send(cToken, 'harnessSetReserveFactorFresh', [etherUnsigned(1e17)]); + await pretendBlock(cToken) + + const expectedAccrualBlockNumber = blockNumber + 1; + const expectedBorrowIndex = borrowIndex + borrowRate * 1e18; + const expectedTotalBorrows = 1e22 + 1e18; + const expectedTotalReserves = 1e20 + 1e17; + + assert.success(await send(cToken, 'accrueInterest')); + assert.equal(await call(cToken, 'accrualBlockNumber'), expectedAccrualBlockNumber); + assert.equal(await call(cToken, 'borrowIndex'), expectedBorrowIndex); + assert.equal(await call(cToken, 'totalBorrows'), expectedTotalBorrows); + assert.equal(await call(cToken, 'totalReserves'), expectedTotalReserves); + }); + }); +}); diff --git a/test/Tokens/adminTest.js b/test/Tokens/adminTest.js new file mode 100644 index 000000000..85f44decf --- /dev/null +++ b/test/Tokens/adminTest.js @@ -0,0 +1,109 @@ +const {address, call, send} = require('../Utils/MochaTruffle'); +const {makeCToken} = require('../Utils/Compound'); + +contract('admin / _setPendingAdmin / _acceptAdmin', function([root, ...accounts]) { + let cToken; + beforeEach(async () => { + cToken = await makeCToken(); + }); + + describe('admin()', async () => { + it('should return correct admin', async () => { + assert.equal(await call(cToken, 'admin'), root); + }); + }); + + describe('pendingAdmin()', async () => { + it('should return correct pending admin', async () => { + assert.addressZero(await call(cToken, 'pendingAdmin')); + }); + }); + + describe('_setPendingAdmin()', async () => { + it('should only be callable by admin', async () => { + assert.hasTokenFailure( + await send(cToken, '_setPendingAdmin', [accounts[0]], {from: accounts[0]}), + 'UNAUTHORIZED', + 'SET_PENDING_ADMIN_OWNER_CHECK' + ); + + // Check admin stays the same + assert.equal(await call(cToken, 'admin'), root); + assert.addressZero(await call(cToken, 'pendingAdmin')); + }); + + it('should properly set pending admin', async () => { + assert.success(await send(cToken, '_setPendingAdmin', [accounts[0]])); + + // Check admin stays the same + assert.equal(await call(cToken, 'admin'), root); + assert.equal(await call(cToken, 'pendingAdmin'), accounts[0]); + }); + + it('should properly set pending admin twice', async () => { + assert.success(await send(cToken, '_setPendingAdmin', [accounts[0]])); + assert.success(await send(cToken, '_setPendingAdmin', [accounts[1]])); + + // Check admin stays the same + assert.equal(await call(cToken, 'admin'), root); + assert.equal(await call(cToken, 'pendingAdmin'), accounts[1]); + }); + + it('should emit event', async () => { + const result = await send(cToken, '_setPendingAdmin', [accounts[0]]); + assert.hasLog(result, 'NewPendingAdmin', { + oldPendingAdmin: address(0), + newPendingAdmin: accounts[0], + }); + }); + }); + + describe('_acceptAdmin()', async () => { + it('should fail when pending admin is zero', async () => { + assert.hasTokenFailure( + await send(cToken, '_acceptAdmin'), + 'UNAUTHORIZED', + 'ACCEPT_ADMIN_PENDING_ADMIN_CHECK' + ); + + // Check admin stays the same + assert.equal(await call(cToken, 'admin'), root); + assert.addressZero(await call(cToken, 'pendingAdmin')); + }); + + it('should fail when called by another account (e.g. root)', async () => { + assert.success(await send(cToken, '_setPendingAdmin', [accounts[0]])); + assert.hasTokenFailure( + await send(cToken, '_acceptAdmin'), + 'UNAUTHORIZED', + 'ACCEPT_ADMIN_PENDING_ADMIN_CHECK' + ); + + // Check admin stays the same + assert.equal(await call(cToken, 'admin'), root); + assert.equal(await call(cToken, 'pendingAdmin') [accounts[0]]); + }); + + it('should succeed and set admin and clear pending admin', async () => { + assert.success(await send(cToken, '_setPendingAdmin', [accounts[0]])); + assert.success(await send(cToken, '_acceptAdmin', [], {from: accounts[0]})); + + // Check admin stays the same + assert.equal(await call(cToken, 'admin'), accounts[0]); + assert.addressZero(await call(cToken, 'pendingAdmin')); + }); + + it('should emit log on success', async () => { + assert.success(await send(cToken, '_setPendingAdmin', [accounts[0]])); + const result = await send(cToken, '_acceptAdmin', [], {from: accounts[0]}); + assert.hasLog(result, 'NewAdmin', { + oldAdmin: root, + newAdmin: accounts[0], + }); + assert.hasLog(result, 'NewPendingAdmin', { + oldPendingAdmin: accounts[0], + newPendingAdmin: address(0), + }); + }); + }); +}); diff --git a/test/Tokens/borrowAndRepayCEtherTest.js b/test/Tokens/borrowAndRepayCEtherTest.js new file mode 100644 index 000000000..e024c7238 --- /dev/null +++ b/test/Tokens/borrowAndRepayCEtherTest.js @@ -0,0 +1,362 @@ +const { + etherGasCost, + etherUnsigned, + etherMantissa, + call, + send +} = require('../Utils/MochaTruffle'); + +const { + makeCToken, + balanceOf, + borrowSnapshot, + totalBorrows, + fastForward, + setBalance, + preApprove, + pretendBorrow, + setEtherBalance, + getBalances, + adjustBalances +} = require('../Utils/Compound'); + +const BigNumber = require('bignumber.js'); + +const borrowAmount = etherUnsigned(10e3); +const repayAmount = etherUnsigned(10e2); + +async function preBorrow(cToken, borrower, borrowAmount) { + await send(cToken.comptroller, 'setBorrowAllowed', [true]); + await send(cToken.comptroller, 'setBorrowVerify', [true]); + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + await send(cToken, 'harnessSetFailTransferToAddress', [borrower, false]); + await send(cToken, 'harnessSetAccountBorrows', [borrower, 0, 0]); + await send(cToken, 'harnessSetTotalBorrows', [0]); + await setEtherBalance(cToken, borrowAmount); +} + +async function borrowFresh(cToken, borrower, borrowAmount) { + return send(cToken, 'harnessBorrowFresh', [borrower, borrowAmount], {from: borrower}); +} + +async function borrow(cToken, borrower, borrowAmount, opts = {}) { + return send(cToken, 'borrow', [borrowAmount], {from: borrower}); +} + +async function preRepay(cToken, benefactor, borrower, repayAmount) { + // setup either benefactor OR borrower for success in repaying + await send(cToken.comptroller, 'setRepayBorrowAllowed', [true]); + await send(cToken.comptroller, 'setRepayBorrowVerify', [true]); + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + await pretendBorrow(cToken, borrower, 1, 1, repayAmount); +} + +async function repayBorrowFresh(cToken, payer, borrower, repayAmount) { + return send(cToken, 'harnessRepayBorrowFresh', [payer, borrower, repayAmount], {from: payer, value: repayAmount}); +} + +async function repayBorrow(cToken, borrower, repayAmount) { + return send(cToken, 'repayBorrow', [], {from: borrower, value: repayAmount}); +} + +async function repayBorrowBehalf(cToken, payer, borrower, repayAmount) { + return send(cToken, 'repayBorrowBehalf', [borrower], {from: payer, value: repayAmount}); +} + +contract('CEther', function ([root, borrower, benefactor, ...accounts]) { + let cToken; + before(async () => { + cToken = await makeCToken({kind: 'cether', comptrollerOpts: {kind: 'bool'}}); + }); + + describe('borrowFresh', async () => { + beforeEach(async () => await preBorrow(cToken, borrower, borrowAmount)); + + it("fails if comptroller tells it to", async () => { + await send(cToken.comptroller, 'setBorrowAllowed', [false]); + assert.hasTrollReject( + await borrowFresh(cToken, borrower, borrowAmount), + 'BORROW_COMPTROLLER_REJECTION' + ); + }); + + it("proceeds if comptroller tells it to", async () => { + await assert.success(await borrowFresh(cToken, borrower, borrowAmount)); + }); + + it("fails if market not fresh", async () => { + await fastForward(cToken); + assert.hasTokenFailure( + await borrowFresh(cToken, borrower, borrowAmount), + 'MARKET_NOT_FRESH', + 'BORROW_FRESHNESS_CHECK' + ); + }); + + it("continues if fresh", async () => { + await assert.succeeds(cToken, 'accrueInterest'); + await assert.success(await borrowFresh(cToken, borrower, borrowAmount)); + }); + + it("fails if protocol has less than borrowAmount of underlying", async () => { + assert.hasTokenFailure( + await borrowFresh(cToken, borrower, borrowAmount.add(1)), + 'TOKEN_INSUFFICIENT_CASH', + 'BORROW_CASH_NOT_AVAILABLE' + ); + }); + + it("fails if borrowBalanceStored fails (due to non-zero stored principal with zero account index)", async () => { + await pretendBorrow(cToken, borrower, 0, 3e18, 5e18); + assert.hasTokenFailure( + await borrowFresh(cToken, borrower, borrowAmount), + 'MATH_ERROR', + 'BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED' + ); + }); + + it("fails if calculating account new total borrow balance overflows", async () => { + await pretendBorrow(cToken, borrower, 1e-18, 1e-18, -1); + assert.hasTokenFailure( + await borrowFresh(cToken, borrower, borrowAmount), + 'MATH_ERROR', + 'BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED' + ); + }); + + it("fails if calculation of new total borrow balance overflows", async () => { + await send(cToken, 'harnessSetTotalBorrows', [-1]); + assert.hasTokenFailure( + await borrowFresh(cToken, borrower, borrowAmount), + 'MATH_ERROR', + 'BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED', + ); + }); + + it("reverts if transfer out fails", async () => { + await send(cToken, 'harnessSetFailTransferToAddress', [borrower, true]); + await assert.revert(borrowFresh(cToken, borrower, borrowAmount), "revert borrow transfer out failed"); + }); + + it("reverts if borrowVerify fails", async() => { + await send(cToken.comptroller, 'setBorrowVerify', [false]); + await assert.revert(borrowFresh(cToken, borrower, borrowAmount), "revert borrowVerify rejected borrow"); + }); + + it("transfers the underlying cash, tokens, and emits Borrow event", async () => { + const beforeBalances = await getBalances([cToken], [borrower]); + const beforeProtocolBorrows = await totalBorrows(cToken); + const result = await borrowFresh(cToken, borrower, borrowAmount); + const afterBalances = await getBalances([cToken], [borrower]); + assert.success(result); + assert.deepEqual(afterBalances, await adjustBalances(beforeBalances, [ + [cToken, 'eth', -borrowAmount], + [cToken, 'borrows', borrowAmount], + [cToken, borrower, 'eth', borrowAmount.sub(await etherGasCost(result))], + [cToken, borrower, 'borrows', borrowAmount] + ])); + assert.hasLog(result, 'Borrow', { + borrower: borrower, + borrowAmount: borrowAmount.toString(), + accountBorrows: borrowAmount.toString(), + totalBorrows: beforeProtocolBorrows.add(borrowAmount).toString() + }); + }); + + it("stores new borrow principal and interest index", async () => { + const beforeProtocolBorrows = await totalBorrows(cToken); + await pretendBorrow(cToken, borrower, 0, 3, 0); + await borrowFresh(cToken, borrower, borrowAmount); + const borrowSnap = await borrowSnapshot(cToken, borrower); + assert.numEqual(borrowSnap.principal, borrowAmount); + assert.numEqual(borrowSnap.interestIndex, etherMantissa(3)); + assert.numEqual(await totalBorrows(cToken), beforeProtocolBorrows.add(borrowAmount)); + }); + }); + + describe('borrow', async () => { + beforeEach(async () => await preBorrow(cToken, borrower, borrowAmount)); + + it("emits a borrow failure if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + assert.hasTokenFailure( + await borrow(cToken, borrower, borrowAmount), + 'INTEREST_RATE_MODEL_ERROR', + 'BORROW_ACCRUE_INTEREST_FAILED' + ); + }); + + it("returns error from borrowFresh without emitting any extra logs", async () => { + assert.hasTokenFailure( + await borrow(cToken, borrower, borrowAmount.add(1)), + 'TOKEN_INSUFFICIENT_CASH', + 'BORROW_CASH_NOT_AVAILABLE' + ); + }); + + it("returns success from borrowFresh and transfers the correct amount", async () => { + const beforeBalances = await getBalances([cToken], [borrower]); + await fastForward(cToken); + const result = await borrow(cToken, borrower, borrowAmount); + const afterBalances = await getBalances([cToken], [borrower]); + assert.success(result); + assert.deepEqual(afterBalances, await adjustBalances(beforeBalances, [ + [cToken, 'eth', -borrowAmount], + [cToken, 'borrows', borrowAmount], + [cToken, borrower, 'eth', borrowAmount.sub(await etherGasCost(result))], + [cToken, borrower, 'borrows', borrowAmount] + ])); + }); + }); + + describe('repayBorrowFresh', async () => { + [benefactor, borrower].forEach(async (payer) => { + const label = benefactor == payer ? "benefactor paying" : "borrower paying"; + describe(label, () => { + beforeEach(async () => { + await preRepay(cToken, payer, borrower, repayAmount); + }); + + it("fails if repay is not allowed", async () => { + await send(cToken.comptroller, 'setRepayBorrowAllowed', [false]); + assert.hasTrollReject( + await repayBorrowFresh(cToken, payer, borrower, repayAmount), + 'REPAY_BORROW_COMPTROLLER_REJECTION', + 'MATH_ERROR' + ); + }); + + it("fails if block number ≠ current block number", async () => { + await fastForward(cToken); + assert.hasTokenFailure( + await repayBorrowFresh(cToken, payer, borrower, repayAmount), + 'MARKET_NOT_FRESH', + 'REPAY_BORROW_FRESHNESS_CHECK' + ); + }); + + it("returns an error if calculating account new account borrow balance fails", async () => { + await pretendBorrow(cToken, borrower, 1, 1, 1); + assert.hasTokenMathFail( + await repayBorrowFresh(cToken, payer, borrower, repayAmount), + 'REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED', + 'INTEGER_UNDERFLOW' + ); + }); + + it("returns an error if calculation of new total borrow balance fails", async () => { + await send(cToken, 'harnessSetTotalBorrows', [1]); + assert.hasTokenMathFail( + await repayBorrowFresh(cToken, payer, borrower, repayAmount), + 'REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED', + 'INTEGER_UNDERFLOW' + ); + }); + + it("reverts if checkTransferIn fails", async () => { + await assert.revert(send(cToken, 'harnessRepayBorrowFresh', [payer, borrower, repayAmount], {from: root, value: repayAmount}), "revert sender mismatch"); + await assert.revert(send(cToken, 'harnessRepayBorrowFresh', [payer, borrower, repayAmount], {from: payer, value: 1}), "revert value mismatch"); + }); + + it("reverts if repayBorrowVerify fails", async() => { + await send(cToken.comptroller, 'setRepayBorrowVerify', [false]); + await assert.revert(repayBorrowFresh(cToken, payer, borrower, repayAmount), "revert repayBorrowVerify rejected repayBorrow"); + }); + + it("transfers the underlying cash, and emits RepayBorrow event", async () => { + const beforeBalances = await getBalances([cToken], [borrower]); + const result = await repayBorrowFresh(cToken, payer, borrower, repayAmount); + const afterBalances = await getBalances([cToken], [borrower]); + assert.success(result); + if (borrower == payer) { + assert.deepEqual(afterBalances, await adjustBalances(beforeBalances, [ + [cToken, 'eth', repayAmount], + [cToken, 'borrows', -repayAmount], + [cToken, borrower, 'borrows', -repayAmount], + [cToken, borrower, 'eth', -repayAmount.add(await etherGasCost(result))] + ])); + } else { + assert.deepEqual(afterBalances, await adjustBalances(beforeBalances, [ + [cToken, 'eth', repayAmount], + [cToken, 'borrows', -repayAmount], + [cToken, borrower, 'borrows', -repayAmount], + ])); + } + assert.hasLog(result, 'RepayBorrow', { + payer: payer, + borrower: borrower, + repayAmount: repayAmount.toString(), + accountBorrows: "0", + totalBorrows: "0" + }); + }); + + it("stores new borrow principal and interest index", async () => { + const beforeProtocolBorrows = await totalBorrows(cToken); + const beforeAccountBorrowSnap = await borrowSnapshot(cToken, borrower); + assert.success(await repayBorrowFresh(cToken, payer, borrower, repayAmount)); + const afterAccountBorrows = await borrowSnapshot(cToken, borrower); + assert.numEqual(afterAccountBorrows.principal, beforeAccountBorrowSnap.principal.sub(repayAmount)); + assert.numEqual(afterAccountBorrows.interestIndex, etherMantissa(1)); + assert.numEqual(await totalBorrows(cToken), beforeProtocolBorrows.sub(repayAmount)); + }); + }); + }); + }); + + describe('repayBorrow', async () => { + beforeEach(async () => { + await preRepay(cToken, borrower, borrower, repayAmount); + }); + + it("reverts if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + await assert.revertWithError(repayBorrow(cToken, borrower, repayAmount), 'INTEREST_RATE_MODEL_ERROR', "revert repayBorrow failed"); + }); + + it("reverts when repay borrow fresh fails", async () => { + await send(cToken.comptroller, 'setRepayBorrowAllowed', [false]); + await assert.revertWithError(repayBorrow(cToken, borrower, repayAmount), 'COMPTROLLER_REJECTION', "revert repayBorrow failed"); + }); + + it("returns success from repayBorrowFresh and repays the right amount", async () => { + await fastForward(cToken); + const beforeAccountBorrowSnap = await borrowSnapshot(cToken, borrower); + assert.success(await repayBorrow(cToken, borrower, repayAmount)); + const afterAccountBorrowSnap = await borrowSnapshot(cToken, borrower); + assert.numEqual(afterAccountBorrowSnap.principal, beforeAccountBorrowSnap.principal.sub(repayAmount)); + }); + + it("reverts if overpaying", async () => { + const beforeAccountBorrowSnap = await borrowSnapshot(cToken, borrower); + let tooMuch = new BigNumber(beforeAccountBorrowSnap.principal).plus(1); + await assert.revertWithError(repayBorrow(cToken, borrower, tooMuch), 'MATH_ERROR', "revert repayBorrow failed"); + }); + }); + + describe('repayBorrowBehalf', async () => { + const payer = benefactor; + + beforeEach(async () => { + await preRepay(cToken, payer, borrower, repayAmount); + }); + + it("reverts if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + await assert.revertWithError(repayBorrowBehalf(cToken, payer, borrower, repayAmount), 'INTEREST_RATE_MODEL_ERROR', "revert repayBorrowBehalf failed"); + }); + + it("reverts from within repay borrow fresh", async () => { + await send(cToken.comptroller, 'setRepayBorrowAllowed', [false]); + await assert.revertWithError(repayBorrowBehalf(cToken, payer, borrower, repayAmount), 'COMPTROLLER_REJECTION', "revert repayBorrowBehalf failed"); + }); + + it("returns success from repayBorrowFresh and repays the right amount", async () => { + await fastForward(cToken); + const beforeAccountBorrowSnap = await borrowSnapshot(cToken, borrower); + assert.success(await repayBorrowBehalf(cToken, payer, borrower, repayAmount)); + const afterAccountBorrowSnap = await borrowSnapshot(cToken, borrower); + assert.numEqual(afterAccountBorrowSnap.principal, beforeAccountBorrowSnap.principal.sub(repayAmount)); + }); + }); +}); diff --git a/test/Tokens/borrowAndRepayTest.js b/test/Tokens/borrowAndRepayTest.js new file mode 100644 index 000000000..76c11f22d --- /dev/null +++ b/test/Tokens/borrowAndRepayTest.js @@ -0,0 +1,390 @@ +const { + etherUnsigned, + etherMantissa, + call, + send +} = require('../Utils/MochaTruffle'); + +const { + makeCToken, + balanceOf, + borrowSnapshot, + totalBorrows, + fastForward, + setBalance, + preApprove, + pretendBorrow +} = require('../Utils/Compound'); + +const borrowAmount = etherUnsigned(10e3); +const repayAmount = etherUnsigned(10e2); + +async function preBorrow(cToken, borrower, borrowAmount) { + await send(cToken.comptroller, 'setBorrowAllowed', [true]); + await send(cToken.comptroller, 'setBorrowVerify', [true]); + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + await send(cToken.underlying, 'harnessSetBalance', [cToken._address, borrowAmount]); + await send(cToken, 'harnessSetFailTransferToAddress', [borrower, false]); + await send(cToken, 'harnessSetAccountBorrows', [borrower, 0, 0]); + await send(cToken, 'harnessSetTotalBorrows', [0]); +} + +async function borrowFresh(cToken, borrower, borrowAmount) { + return send(cToken, 'harnessBorrowFresh', [borrower, borrowAmount]); +} + +async function borrow(cToken, borrower, borrowAmount, opts = {}) { + return send(cToken, 'borrow', [borrowAmount], {from: borrower}); +} + +async function preRepay(cToken, benefactor, borrower, repayAmount) { + // setup either benefactor OR borrower for success in repaying + await send(cToken.comptroller, 'setRepayBorrowAllowed', [true]); + await send(cToken.comptroller, 'setRepayBorrowVerify', [true]); + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + await send(cToken.underlying, 'harnessSetFailTransferFromAddress', [benefactor, false]); + await send(cToken.underlying, 'harnessSetFailTransferFromAddress', [borrower, false]); + await pretendBorrow(cToken, borrower, 1, 1, repayAmount); + await preApprove(cToken, benefactor, repayAmount); + await preApprove(cToken, borrower, repayAmount); +} + +async function repayBorrowFresh(cToken, payer, borrower, repayAmount) { + return send(cToken, 'harnessRepayBorrowFresh', [payer, borrower, repayAmount], {from: payer}); +} + +async function repayBorrow(cToken, borrower, repayAmount) { + return send(cToken, 'repayBorrow', [repayAmount], {from: borrower}); +} + +async function repayBorrowBehalf(cToken, payer, borrower, repayAmount) { + return send(cToken, 'repayBorrowBehalf', [borrower, repayAmount], {from: payer}); +} + +contract('CToken', function ([root, borrower, benefactor, ...accounts]) { + let cToken; + before(async () => { + cToken = await makeCToken({comptrollerOpts: {kind: 'bool'}}); + }); + + describe('borrowFresh', async () => { + beforeEach(async () => await preBorrow(cToken, borrower, borrowAmount)); + + it("fails if comptroller tells it to", async () => { + await send(cToken.comptroller, 'setBorrowAllowed', [false]); + assert.hasTrollReject( + await borrowFresh(cToken, borrower, borrowAmount), + 'BORROW_COMPTROLLER_REJECTION' + ); + }); + + it("proceeds if comptroller tells it to", async () => { + await assert.success(await borrowFresh(cToken, borrower, borrowAmount)); + }); + + it("fails if market not fresh", async () => { + await fastForward(cToken); + assert.hasTokenFailure( + await borrowFresh(cToken, borrower, borrowAmount), + 'MARKET_NOT_FRESH', + 'BORROW_FRESHNESS_CHECK' + ); + }); + + it("continues if fresh", async () => { + await assert.succeeds(cToken, 'accrueInterest'); + await assert.success(await borrowFresh(cToken, borrower, borrowAmount)); + }); + + it("fails if error if protocol has less than borrowAmount of underlying", async () => { + assert.hasTokenFailure( + await borrowFresh(cToken, borrower, borrowAmount.add(1)), + 'TOKEN_INSUFFICIENT_CASH', + 'BORROW_CASH_NOT_AVAILABLE' + ); + }); + + it("fails if borrowBalanceStored fails (due to non-zero stored principal with zero account index)", async () => { + await pretendBorrow(cToken, borrower, 0, 3e18, 5e18); + assert.hasTokenFailure( + await borrowFresh(cToken, borrower, borrowAmount), + 'MATH_ERROR', + 'BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED' + ); + }); + + it("fails if calculating account new total borrow balance overflows", async () => { + await pretendBorrow(cToken, borrower, 1e-18, 1e-18, -1); + assert.hasTokenFailure( + await borrowFresh(cToken, borrower, borrowAmount), + 'MATH_ERROR', + 'BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED' + ); + }); + + it("fails if calculation of new total borrow balance overflows", async () => { + await send(cToken, 'harnessSetTotalBorrows', [-1]); + assert.hasTokenFailure( + await borrowFresh(cToken, borrower, borrowAmount), + 'MATH_ERROR', + 'BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED', + ); + }); + + it("reverts if transfer out fails", async () => { + await send(cToken, 'harnessSetFailTransferToAddress', [borrower, true]); + await assert.revert(borrowFresh(cToken, borrower, borrowAmount), "revert borrow transfer out failed"); + }); + + it("reverts if borrowVerify fails", async() => { + await send(cToken.comptroller, 'setBorrowVerify', [false]); + await assert.revert(borrowFresh(cToken, borrower, borrowAmount), "revert borrowVerify rejected borrow"); + }); + + it("transfers the underlying cash, tokens, and emits Transfer, Borrow events", async () => { + const beforeProtocolCash = await balanceOf(cToken.underlying, cToken._address); + const beforeProtocolBorrows = await totalBorrows(cToken); + const beforeAccountCash = await balanceOf(cToken.underlying, borrower); + const result = await borrowFresh(cToken, borrower, borrowAmount); + assert.success(result); + assert.numEqual(await balanceOf(cToken.underlying, borrower), beforeAccountCash.add(borrowAmount)); + assert.numEqual(await balanceOf(cToken.underlying, cToken._address), beforeProtocolCash.sub(borrowAmount)); + assert.numEqual(await totalBorrows(cToken), beforeProtocolBorrows.add(borrowAmount)); + assert.hasLog(result, 'Transfer', { + from: cToken._address, + to: borrower, + amount: borrowAmount.toString() + }); + assert.hasLog(result, 'Borrow', { + borrower: borrower, + borrowAmount: borrowAmount.toString(), + accountBorrows: borrowAmount.toString(), + totalBorrows: beforeProtocolBorrows.add(borrowAmount).toString() + }); + }); + + it("stores new borrow principal and interest index", async () => { + const beforeProtocolBorrows = await totalBorrows(cToken); + await pretendBorrow(cToken, borrower, 0, 3, 0); + await borrowFresh(cToken, borrower, borrowAmount); + const borrowSnap = await borrowSnapshot(cToken, borrower); + assert.numEqual(borrowSnap.principal, borrowAmount); + assert.numEqual(borrowSnap.interestIndex, etherMantissa(3)); + assert.numEqual(await totalBorrows(cToken), beforeProtocolBorrows.add(borrowAmount)); + }); + }); + + describe('borrow', async () => { + beforeEach(async () => await preBorrow(cToken, borrower, borrowAmount)); + + it("emits a borrow failure if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + assert.hasTokenFailure( + await borrow(cToken, borrower, borrowAmount), + 'INTEREST_RATE_MODEL_ERROR', + 'BORROW_ACCRUE_INTEREST_FAILED' + ); + }); + + it("returns error from borrowFresh without emitting any extra logs", async () => { + assert.hasTokenFailure( + await borrow(cToken, borrower, borrowAmount.add(1)), + 'TOKEN_INSUFFICIENT_CASH', + 'BORROW_CASH_NOT_AVAILABLE' + ); + }); + + it("returns success from borrowFresh and transfers the correct amount", async () => { + const beforeAccountCash = await balanceOf(cToken.underlying, borrower); + await fastForward(cToken); + assert.success(await borrow(cToken, borrower, borrowAmount)); + assert.numEqual(await balanceOf(cToken.underlying, borrower), beforeAccountCash.add(borrowAmount)); + }); + }); + + describe('repayBorrowFresh', async () => { + [benefactor, borrower].forEach(async (payer) => { + const label = benefactor == payer ? "benefactor paying" : "borrower paying"; + describe(label, () => { + beforeEach(async () => { + await preRepay(cToken, payer, borrower, repayAmount); + }); + + it("fails if repay is not allowed", async () => { + await send(cToken.comptroller, 'setRepayBorrowAllowed', [false]); + assert.hasTrollReject( + await repayBorrowFresh(cToken, payer, borrower, repayAmount), + 'REPAY_BORROW_COMPTROLLER_REJECTION', + 'MATH_ERROR' + ); + }); + + it("fails if block number ≠ current block number", async () => { + await fastForward(cToken); + assert.hasTokenFailure( + await repayBorrowFresh(cToken, payer, borrower, repayAmount), + 'MARKET_NOT_FRESH', + 'REPAY_BORROW_FRESHNESS_CHECK' + ); + }); + + it("fails if insufficient approval", async() => { + await preApprove(cToken, payer, 1); + assert.hasTokenFailure( + await repayBorrowFresh(cToken, payer, borrower, repayAmount), + 'TOKEN_INSUFFICIENT_ALLOWANCE', + 'REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE' + ); + }); + + it("fails if insufficient balance", async() => { + await setBalance(cToken.underlying, payer, 1); + assert.hasTokenFailure( + await repayBorrowFresh(cToken, payer, borrower, repayAmount), + 'TOKEN_INSUFFICIENT_BALANCE', + 'REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE' + ); + }); + + it("returns an error if calculating account new account borrow balance fails", async () => { + await pretendBorrow(cToken, borrower, 1, 1, 1); + assert.hasTokenMathFail( + await repayBorrowFresh(cToken, payer, borrower, repayAmount), + 'REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED', + 'INTEGER_UNDERFLOW' + ); + }); + + it("returns an error if calculation of new total borrow balance fails", async () => { + await send(cToken, 'harnessSetTotalBorrows', [1]); + assert.hasTokenMathFail( + await repayBorrowFresh(cToken, payer, borrower, repayAmount), + 'REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED', + 'INTEGER_UNDERFLOW' + ); + }); + + it("reverts if doTransferIn fails", async () => { + await send(cToken.underlying, 'harnessSetFailTransferFromAddress', [payer, true]); + await assert.revert(repayBorrowFresh(cToken, payer, borrower, repayAmount), "revert repay borrow transfer in failed"); + }); + + it("reverts if repayBorrowVerify fails", async() => { + await send(cToken.comptroller, 'setRepayBorrowVerify', [false]); + await assert.revert(repayBorrowFresh(cToken, payer, borrower, repayAmount), "revert repayBorrowVerify rejected repayBorrow"); + }); + + it("transfers the underlying cash, and emits Transfer, RepayBorrow events", async () => { + const beforeProtocolCash = await balanceOf(cToken.underlying, cToken._address); + const result = await repayBorrowFresh(cToken, payer, borrower, repayAmount); + assert.numEqual(await balanceOf(cToken.underlying, cToken._address), beforeProtocolCash.add(repayAmount)); + assert.hasLog(result, 'Transfer', { + from: payer, + to: cToken._address, + amount: repayAmount.toString() + }); + assert.hasLog(result, 'RepayBorrow', { + payer: payer, + borrower: borrower, + repayAmount: repayAmount.toString(), + accountBorrows: "0", + totalBorrows: "0" + }); + }); + + it("stores new borrow principal and interest index", async () => { + const beforeProtocolBorrows = await totalBorrows(cToken); + const beforeAccountBorrowSnap = await borrowSnapshot(cToken, borrower); + assert.success(await repayBorrowFresh(cToken, payer, borrower, repayAmount)); + const afterAccountBorrows = await borrowSnapshot(cToken, borrower); + assert.numEqual(afterAccountBorrows.principal, beforeAccountBorrowSnap.principal.sub(repayAmount)); + assert.numEqual(afterAccountBorrows.interestIndex, etherMantissa(1)); + assert.numEqual(await totalBorrows(cToken), beforeProtocolBorrows.sub(repayAmount)); + }); + }); + }); + }); + + describe('repayBorrow', async () => { + beforeEach(async () => { + await preRepay(cToken, borrower, borrower, repayAmount); + }); + + it("emits a repay borrow failure if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + assert.hasTokenFailure( + await repayBorrow(cToken, borrower, repayAmount), + 'INTEREST_RATE_MODEL_ERROR', + 'REPAY_BORROW_ACCRUE_INTEREST_FAILED' + ); + }); + + it("returns error from repayBorrowFresh without emitting any extra logs", async () => { + await setBalance(cToken.underlying, borrower, 1); + assert.hasTokenFailure( + await repayBorrow(cToken, borrower, repayAmount), + 'TOKEN_INSUFFICIENT_BALANCE', + 'REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE' + ); + }); + + it("returns success from repayBorrowFresh and repays the right amount", async () => { + await fastForward(cToken); + const beforeAccountBorrowSnap = await borrowSnapshot(cToken, borrower); + assert.success(await repayBorrow(cToken, borrower, repayAmount)); + const afterAccountBorrowSnap = await borrowSnapshot(cToken, borrower); + assert.numEqual(afterAccountBorrowSnap.principal, beforeAccountBorrowSnap.principal.sub(repayAmount)); + }); + + it("repays the full amount owed if payer has enough", async () => { + await fastForward(cToken); + assert.success(await repayBorrow(cToken, borrower, -1)); + const afterAccountBorrowSnap = await borrowSnapshot(cToken, borrower); + assert.numEqual(afterAccountBorrowSnap.principal, 0); + }); + + it("fails gracefully if payer does not have enough", async () => { + await setBalance(cToken.underlying, borrower, 3); + await fastForward(cToken); + assert.hasTokenFailure( + await repayBorrow(cToken, borrower, -1), + 'TOKEN_INSUFFICIENT_BALANCE', + 'REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE' + ); + }); + }); + + describe('repayBorrowBehalf', async () => { + const payer = benefactor; + + beforeEach(async () => { + await preRepay(cToken, payer, borrower, repayAmount); + }); + + it("emits a repay borrow failure if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + assert.hasTokenFailure( + await repayBorrowBehalf(cToken, payer, borrower, repayAmount), + 'INTEREST_RATE_MODEL_ERROR', + 'REPAY_BEHALF_ACCRUE_INTEREST_FAILED' + ); + }); + + it("returns error from repayBorrowFresh without emitting any extra logs", async () => { + await setBalance(cToken.underlying, payer, 1); + assert.hasTokenFailure( + await repayBorrowBehalf(cToken, payer, borrower, repayAmount), + 'TOKEN_INSUFFICIENT_BALANCE', + 'REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE' + ); + }); + + it("returns success from repayBorrowFresh and repays the right amount", async () => { + await fastForward(cToken); + const beforeAccountBorrowSnap = await borrowSnapshot(cToken, borrower); + assert.success(await repayBorrowBehalf(cToken, payer, borrower, repayAmount)); + const afterAccountBorrowSnap = await borrowSnapshot(cToken, borrower); + assert.numEqual(afterAccountBorrowSnap.principal, beforeAccountBorrowSnap.principal.sub(repayAmount)); + }); + }); +}); diff --git a/test/Tokens/cTokenTest.js b/test/Tokens/cTokenTest.js new file mode 100644 index 000000000..6f4aee6e4 --- /dev/null +++ b/test/Tokens/cTokenTest.js @@ -0,0 +1,200 @@ +const { + etherUnsigned, + etherMantissa, + call, + send +} = require('../Utils/MochaTruffle'); + +const { + makeCToken, + setBorrowRate, + pretendBorrow +} = require('../Utils/Compound'); + +contract('CToken', function ([root, ...accounts]) { + describe('constructor', async () => { + it("fails when non erc-20 underlying", async () => { + await assert.revert(makeCToken({underlying: {_address: root}})); + }); + + it("fails when 0 initial exchange rate", async () => { + await assert.revert(makeCToken({exchangeRate: 0}), "revert Initial exchange rate must be greater than zero."); + }); + + it("succeeds with erc-20 underlying and non-zero exchange rate", async () => { + const cToken = await makeCToken(); + assert.equal(await call(cToken, 'underlying'), cToken.underlying._address); + assert.equal(await call(cToken, 'admin',), root); + }); + }); + + describe('name, symbol, decimals', async () => { + let cToken; + before(async () => { + cToken = await makeCToken({name: "CToken Foo", symbol: "cFOO", decimals: 10}); + }); + + it('should return correct name', async () => { + assert.equal(await call(cToken, 'name'), "CToken Foo"); + }); + + it('should return correct symbol', async () => { + assert.equal(await call(cToken, 'symbol'), "cFOO"); + }); + + it('should return correct decimals', async () => { + assert.equal(await call(cToken, 'decimals'), 10); + }); + }); + + describe('balanceOfUnderlying', () => { + it("has an underlying balance", async () => { + const cToken = await makeCToken({supportMarket: true, exchangeRate: 2}); + await send(cToken, 'harnessSetBalance', [root, 100]); + assert.equal(await call(cToken, 'balanceOfUnderlying', [root]), 200); + }); + }); + + describe('borrowRatePerBlock', () => { + it("has a borrow rate", async () => { + const cToken = await makeCToken({supportMarket: true, interestRateModelOpts: {kind: 'white-paper', baseRate: .05, multiplier: 0.45}}); + const perBlock = await call(cToken, 'borrowRatePerBlock'); + assert.approximately(perBlock * 2102400, 5e16, 1e8); + }); + }); + + describe('supplyRatePerBlock', () => { + it("reverts if there's no supply", async () => { + const cToken = await makeCToken({supportMarket: true, interestRateModelOpts: {kind: 'white-paper', baseRate: .05, multiplier: 0.45}}); + await assert.revert(call(cToken, 'supplyRatePerBlock'), "revert supplyRatePerBlock: calculating borrowsPer failed"); + }); + + it("has a supply rate", async () => { + const cToken = await makeCToken({supportMarket: true, interestRateModelOpts: {kind: 'white-paper', baseRate: .05, multiplier: 0.45}}); + await send(cToken, 'harnessSetReserveFactorFresh', [etherMantissa(.01)]); + await send(cToken, 'harnessExchangeRateDetails', [1, 1, 0]); + await send(cToken, 'harnessSetExchangeRate', [etherMantissa(1)]); + const perBlock = await call(cToken, 'supplyRatePerBlock'); + assert.approximately(perBlock * 2102400, 50e16 * .99, 1e8); // full utilization, 1% reserves + }); + }); + + describe("borrowBalanceCurrent", async () => { + const borrower = accounts[0]; + + let cToken; + before(async () => { + cToken = await makeCToken(); + }); + + beforeEach(async () => { + await setBorrowRate(cToken, .001) + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + }); + + it("reverts if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + await assert.revert(send(cToken, 'borrowBalanceCurrent', [borrower]), "revert accrue interest failed"); + }); + + it("returns successful result from borrowBalanceStored with no interest", async () => { + await setBorrowRate(cToken, 0); + await pretendBorrow(cToken, borrower, 1, 1, 5e18); + assert.equal(await call(cToken, 'borrowBalanceCurrent', [borrower]), 5e18) + }); + + it("returns successful result from borrowBalanceCurrent with no interest", async () => { + await setBorrowRate(cToken, 0); + await pretendBorrow(cToken, borrower, 1, 3, 5e18); + assert.success(await send(cToken, 'harnessFastForward', [5])); + assert.equal(await call(cToken, 'borrowBalanceCurrent', [borrower]), 5e18 * 3) + }); + }); + + describe("borrowBalanceStored", async () => { + const borrower = accounts[0]; + + let cToken; + beforeEach(async () => { + cToken = await makeCToken({comptrollerOpts: {kind: 'bool'}}); + }); + + it("returns 0 for account with no borrows", async () => { + assert.equal(await call(cToken, 'borrowBalanceStored', [borrower]), 0) + }); + + it("returns stored principal when account and market indexes are the same", async () => { + await pretendBorrow(cToken, borrower, 1, 1, 5e18); + assert.equal(await call(cToken, 'borrowBalanceStored', [borrower]), 5e18); + }); + + it("returns calculated balance when market index is higher than account index", async () => { + await pretendBorrow(cToken, borrower, 1, 3, 5e18); + assert.equal(await call(cToken, 'borrowBalanceStored', [borrower]), 5e18 * 3); + }); + + it("has undefined behavior when market index is lower than account index", async () => { + // The market index < account index should NEVER happen, so we don't test this case + }); + + it("reverts on overflow of principal", async () => { + await pretendBorrow(cToken, borrower, 1, 3, -1); + await assert.revert(call(cToken, 'borrowBalanceStored', [borrower]), "revert borrowBalanceStored: borrowBalanceStoredInternal failed"); + }); + + it("reverts on non-zero stored principal with zero account index", async () => { + await pretendBorrow(cToken, borrower, 0, 3, 5); + await assert.revert(call(cToken, 'borrowBalanceStored', [borrower]), "revert borrowBalanceStored: borrowBalanceStoredInternal failed"); + }); + }); + + describe('exchangeRateStored', async () => { + let cToken, exchangeRate = 2; + beforeEach(async () => { + cToken = await makeCToken({exchangeRate}); + }); + + it("returns initial exchange rate with zero cTokenSupply", async () => { + const result = await call(cToken, 'exchangeRateStored'); + assert.equal(result, etherMantissa(exchangeRate), "exchange rate should be initial exchange rate"); + }); + + it("calculates with single cTokenSupply and single total borrow", async () => { + const cTokenSupply = 1, totalBorrows = 1, totalReserves = 0; + await send(cToken, 'harnessExchangeRateDetails', [cTokenSupply, totalBorrows, totalReserves]); + const result = await call(cToken, 'exchangeRateStored'); + assert.equal(result, etherMantissa(1), "exchange rate should be 1 to 1 (ie: 1e18)"); + }); + + it("calculates with cTokenSupply and total borrows", async () => { + const cTokenSupply = 100e18, totalBorrows = 10e18, totalReserves = 0; + await send(cToken, 'harnessExchangeRateDetails', [cTokenSupply, totalBorrows, totalReserves].map(etherUnsigned)); + const result = await call(cToken, 'exchangeRateStored'); + assert.equal(result, etherMantissa(.1), "exchange rate should be 0.1 (ie: 10e18 / 100e18)"); + }); + + it("calculates with cash and cTokenSupply", async () => { + const cTokenSupply = 5e18, totalBorrows = 0, totalReserves = 0; + assert.success(await send(cToken.underlying, 'transfer', [cToken._address, etherMantissa(500)])); + await send(cToken, 'harnessExchangeRateDetails', [cTokenSupply, totalBorrows, totalReserves].map(etherUnsigned)); + const result = await call(cToken, 'exchangeRateStored'); + assert.equal(result, etherMantissa(100), "exchange rate should be 100 (ie: 500e18 / 5e18)"); + }); + + it("calculates with cash, borrows, reserves and cTokenSupply", async () => { + const cTokenSupply = 500e18, totalBorrows = 500e18, totalReserves = 5e18; + assert.success(await send(cToken.underlying, 'transfer', [cToken._address, etherMantissa(500)])); + await send(cToken, 'harnessExchangeRateDetails', [cTokenSupply, totalBorrows, totalReserves].map(etherUnsigned)); + const result = await call(cToken, 'exchangeRateStored'); + assert.equal(result, etherMantissa(1.99), "exchange rate should be 1.99 (ie: (500e18 + 500e18 - 5e18) / 500e18)"); + }); + }); + + describe('getCash', async () => { + it("gets the cash", async () => { + const cToken = await makeCToken(); + const result = await call(cToken, 'getCash'); + assert.equal(result, 0); + }); + }); +}); diff --git a/test/Tokens/liquidateTest.js b/test/Tokens/liquidateTest.js new file mode 100644 index 000000000..258a284c9 --- /dev/null +++ b/test/Tokens/liquidateTest.js @@ -0,0 +1,270 @@ +const { + etherGasCost, + etherUnsigned, + call, + send +} = require('../Utils/MochaTruffle'); + +const { + makeCToken, + fastForward, + setBalance, + getBalances, + adjustBalances, + pretendBorrow, + preApprove +} = require('../Utils/Compound'); + +const repayAmount = etherUnsigned(10e2); +const seizeAmount = repayAmount; +const seizeTokens = seizeAmount.mul(4); // forced + +async function preLiquidate(cToken, liquidator, borrower, repayAmount, cTokenCollateral) { + // setup for success in liquidating + await send(cToken.comptroller, 'setLiquidateBorrowAllowed', [true]); + await send(cToken.comptroller, 'setLiquidateBorrowVerify', [true]); + await send(cToken.comptroller, 'setRepayBorrowAllowed', [true]); + await send(cToken.comptroller, 'setRepayBorrowVerify', [true]); + await send(cToken.comptroller, 'setSeizeAllowed', [true]); + await send(cToken.comptroller, 'setSeizeVerify', [true]); + await send(cToken.comptroller, 'setFailCalculateSeizeTokens', [false]); + await send(cToken.underlying, 'harnessSetFailTransferFromAddress', [liquidator, false]); + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + await send(cTokenCollateral.interestRateModel, 'setFailBorrowRate', [false]); + await send(cTokenCollateral.comptroller, 'setCalculatedSeizeTokens', [seizeTokens]); + await setBalance(cTokenCollateral, liquidator, 0); + await setBalance(cTokenCollateral, borrower, seizeTokens); + await pretendBorrow(cTokenCollateral, borrower, 0, 1, 0); + await pretendBorrow(cToken, borrower, 1, 1, repayAmount); + await preApprove(cToken, liquidator, repayAmount); +} + +async function liquidateFresh(cToken, liquidator, borrower, repayAmount, cTokenCollateral) { + return send(cToken, 'harnessLiquidateBorrowFresh', [liquidator, borrower, repayAmount, cTokenCollateral._address]); +} + +async function liquidate(cToken, liquidator, borrower, repayAmount, cTokenCollateral) { + return send(cToken, 'liquidateBorrow', [borrower, repayAmount, cTokenCollateral._address], {from: liquidator}); +} + +async function seize(cToken, liquidator, borrower, seizeAmount) { + return send(cToken, 'seize', [liquidator, borrower, seizeAmount]); +} + +contract('CToken', function ([root, liquidator, borrower, ...accounts]) { + let cToken, cTokenCollateral; + before(async () => { + cToken = await makeCToken({comptrollerOpts: {kind: 'bool'}}); + cTokenCollateral = await makeCToken({comptroller: cToken.comptroller}); + }); + + beforeEach(async () => { + await preLiquidate(cToken, liquidator, borrower, repayAmount, cTokenCollateral); + }); + + describe('liquidateBorrowFresh', async () => { + it("fails if comptroller tells it to", async () => { + await send(cToken.comptroller, 'setLiquidateBorrowAllowed', [false]); + assert.hasTrollReject( + await liquidateFresh(cToken, liquidator, borrower, repayAmount, cTokenCollateral), + 'LIQUIDATE_COMPTROLLER_REJECTION', + 'MATH_ERROR' + ); + }); + + it("proceeds if comptroller tells it to", async () => { + assert.success(await liquidateFresh(cToken, liquidator, borrower, repayAmount, cTokenCollateral)); + }); + + it("fails if market not fresh", async () => { + await fastForward(cToken); + assert.hasTokenFailure( + await liquidateFresh(cToken, liquidator, borrower, repayAmount, cTokenCollateral), + 'MARKET_NOT_FRESH', + 'LIQUIDATE_FRESHNESS_CHECK' + ); + }); + + it("fails if collateral market not fresh", async () => { + await fastForward(cToken); + await fastForward(cTokenCollateral); + await send(cToken, 'accrueInterest'); + assert.hasTokenFailure( + await liquidateFresh(cToken, liquidator, borrower, repayAmount, cTokenCollateral), + 'MARKET_NOT_FRESH', + 'LIQUIDATE_COLLATERAL_FRESHNESS_CHECK' + ); + }); + + it("fails if borrower is equal to liquidator", async () => { + assert.hasTokenFailure( + await liquidateFresh(cToken, borrower, borrower, repayAmount, cTokenCollateral), + 'INVALID_ACCOUNT_PAIR', + 'LIQUIDATE_LIQUIDATOR_IS_BORROWER' + ); + }); + + it("fails if repayAmount = 0", async () => { + assert.hasTokenFailure( + await liquidateFresh(cToken, liquidator, borrower, 0, cTokenCollateral), + 'INVALID_CLOSE_AMOUNT_REQUESTED', + 'LIQUIDATE_CLOSE_AMOUNT_IS_ZERO' + ); + }); + + it("fails if calculating seize tokens fails and does not adjust balances", async () => { + const beforeBalances = await getBalances([cToken, cTokenCollateral], [liquidator, borrower]); + await send(cToken.comptroller, 'setFailCalculateSeizeTokens', [true]); + assert.hasTokenFailure( + await liquidateFresh(cToken, liquidator, borrower, repayAmount, cTokenCollateral), + 'COMPTROLLER_CALCULATION_ERROR', + 'LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED', + ); + const afterBalances = await getBalances([cToken, cTokenCollateral], [liquidator, borrower]); + assert.deepEqual(afterBalances, beforeBalances); + }); + + it("fails if repay fails", async () => { + await send(cToken.comptroller, 'setRepayBorrowAllowed', [false]); + assert.hasTrollReject( + await liquidateFresh(cToken, liquidator, borrower, repayAmount, cTokenCollateral), + 'LIQUIDATE_REPAY_BORROW_FRESH_FAILED' + ); + }); + + it("reverts if seize fails", async () => { + await send(cToken.comptroller, 'setSeizeAllowed', [false]); + await assert.revert(liquidateFresh(cToken, liquidator, borrower, repayAmount, cTokenCollateral), "revert token seizure failed"); + }); + + it("reverts if liquidateBorrowVerify fails", async() => { + await send(cToken.comptroller, 'setLiquidateBorrowVerify', [false]); + await assert.revert(liquidateFresh(cToken, liquidator, borrower, repayAmount, cTokenCollateral), "revert liquidateBorrowVerify rejected liquidateBorrow"); + }); + + it("transfers the cash, borrows, tokens, and emits Transfer, LiquidateBorrow events", async () => { + const beforeBalances = await getBalances([cToken, cTokenCollateral], [liquidator, borrower]); + const result = await liquidateFresh(cToken, liquidator, borrower, repayAmount, cTokenCollateral); + const afterBalances = await getBalances([cToken, cTokenCollateral], [liquidator, borrower]); + assert.success(result); + assert.hasLog(result, 'LiquidateBorrow', { + liquidator: liquidator, + borrower: borrower, + repayAmount: repayAmount.toString(), + cTokenCollateral: cTokenCollateral._address, + seizeTokens: seizeTokens.toString() + }); + assert.hasLog(result, ['Transfer', 0], { + from: liquidator, + to: cToken._address, + amount: repayAmount.toString() + }); + assert.hasLog(result, ['Transfer', 1], { + from: borrower, + to: liquidator, + amount: seizeTokens.toString() + }); + assert.deepEqual(afterBalances, await adjustBalances(beforeBalances, [ + [cToken, 'cash', repayAmount], + [cToken, 'borrows', -repayAmount], + [cToken, liquidator, 'cash', -repayAmount], + [cTokenCollateral, liquidator, 'tokens', seizeTokens], + [cToken, borrower, 'borrows', -repayAmount], + [cTokenCollateral, borrower, 'tokens', -seizeTokens] + ])); + }); + }); + + describe('liquidateBorrow', async () => { + it("emits a liquidation failure if borrowed asset interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + assert.hasTokenFailure( + await liquidate(cToken, liquidator, borrower, repayAmount, cTokenCollateral), + 'INTEREST_RATE_MODEL_ERROR', + 'LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED' + ); + }); + + it("emits a liquidation failure if collateral asset interest accrual fails", async () => { + await send(cTokenCollateral.interestRateModel, 'setFailBorrowRate', [true]); + assert.hasTokenFailure( + await liquidate(cToken, liquidator, borrower, repayAmount, cTokenCollateral), + 'INTEREST_RATE_MODEL_ERROR', + 'LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED' + ); + }); + + it("returns error from liquidateBorrowFresh without emitting any extra logs", async () => { + assert.hasTokenFailure( + await liquidate(cToken, liquidator, borrower, 0, cTokenCollateral), + 'INVALID_CLOSE_AMOUNT_REQUESTED', + 'LIQUIDATE_CLOSE_AMOUNT_IS_ZERO' + ); + }); + + it("returns success from liquidateBorrowFresh and transfers the correct amounts", async () => { + const beforeBalances = await getBalances([cToken, cTokenCollateral], [liquidator, borrower]); + const result = await liquidate(cToken, liquidator, borrower, repayAmount, cTokenCollateral); + const gasCost = await etherGasCost(result); + const afterBalances = await getBalances([cToken, cTokenCollateral], [liquidator, borrower]); + assert.success(result); + assert.deepEqual(afterBalances, await adjustBalances(beforeBalances, [ + [cToken, 'cash', repayAmount], + [cToken, 'borrows', -repayAmount], + [cToken, liquidator, 'eth', -gasCost], + [cToken, liquidator, 'cash', -repayAmount], + [cTokenCollateral, liquidator, 'eth', -gasCost], + [cTokenCollateral, liquidator, 'tokens', seizeTokens], + [cToken, borrower, 'borrows', -repayAmount], + [cTokenCollateral, borrower, 'tokens', -seizeTokens] + ])); + }); + }); + + describe('seize', async () => { + // XXX verify callers are properly checked + + it("fails if seize is not allowed", async () => { + await send(cToken.comptroller, 'setSeizeAllowed', [false]); + assert.hasTrollReject( + await seize(cTokenCollateral, liquidator, borrower, seizeTokens), + 'LIQUIDATE_SEIZE_COMPTROLLER_REJECTION', + 'MATH_ERROR' + ); + }); + + it("fails if cTokenBalances[borrower] < amount", async () => { + await setBalance(cTokenCollateral, borrower, 1); + assert.hasTokenMathFail( + await seize(cTokenCollateral, liquidator, borrower, seizeTokens), + 'LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED', + 'INTEGER_UNDERFLOW' + ); + }); + + it("fails if cTokenBalances[liquidator] overflows", async () => { + await setBalance(cTokenCollateral, liquidator, -1); + assert.hasTokenMathFail( + await seize(cTokenCollateral, liquidator, borrower, seizeTokens), + 'LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED', + 'INTEGER_OVERFLOW' + ); + }); + + it("succeeds, updates balances, and emits Transfer event", async () => { + const beforeBalances = await getBalances([cTokenCollateral], [liquidator, borrower]); + const result = await seize(cTokenCollateral, liquidator, borrower, seizeTokens); + const afterBalances = await getBalances([cTokenCollateral], [liquidator, borrower]); + assert.success(result); + assert.hasLog(result, 'Transfer', { + from: borrower, + to: liquidator, + amount: seizeTokens.toString() + }); + assert.deepEqual(afterBalances, await adjustBalances(beforeBalances, [ + [cTokenCollateral, liquidator, 'tokens', seizeTokens], + [cTokenCollateral, borrower, 'tokens', -seizeTokens] + ])); + }); + }); +}); \ No newline at end of file diff --git a/test/Tokens/mintAndRedeemCEtherTest.js b/test/Tokens/mintAndRedeemCEtherTest.js new file mode 100644 index 000000000..deba82e3e --- /dev/null +++ b/test/Tokens/mintAndRedeemCEtherTest.js @@ -0,0 +1,129 @@ +const { + etherGasCost, + etherMantissa, + etherUnsigned, + send, + sendFallback +} = require('../Utils/MochaTruffle'); + +const { + makeCToken, + balanceOf, + fastForward, + setBalance, + setEtherBalance, + getBalances, + adjustBalances, +} = require('../Utils/Compound'); + +const exchangeRate = 5; +const mintAmount = etherUnsigned(1e5); +const mintTokens = mintAmount.div(exchangeRate); +const redeemTokens = etherUnsigned(10e3); +const redeemAmount = redeemTokens.mul(exchangeRate); + +async function preMint(cToken, minter, mintAmount, mintTokens, exchangeRate) { + await send(cToken.comptroller, 'setMintAllowed', [true]); + await send(cToken.comptroller, 'setMintVerify', [true]); + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + await send(cToken, 'harnessSetExchangeRate', [etherMantissa(exchangeRate)]); +} + +async function mintExplicit(cToken, minter, mintAmount) { + return send(cToken, 'mint', [], {from: minter, value: mintAmount}); +} + +async function mintFallback(cToken, minter, mintAmount) { + return sendFallback(cToken, {from: minter, value: mintAmount}); +} + +async function preRedeem(cToken, redeemer, redeemTokens, redeemAmount, exchangeRate) { + await send(cToken.comptroller, 'setRedeemAllowed', [true]); + await send(cToken.comptroller, 'setRedeemVerify', [true]); + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + await send(cToken, 'harnessSetExchangeRate', [etherMantissa(exchangeRate)]); + await setEtherBalance(cToken, redeemAmount); + await setBalance(cToken, redeemer, redeemTokens); +} + +async function redeemCTokens(cToken, redeemer, redeemTokens, redeemAmount) { + return send(cToken, 'redeem', [redeemTokens], {from: redeemer}); +} + +async function redeemUnderlying(cToken, redeemer, redeemTokens, redeemAmount) { + return send(cToken, 'redeemUnderlying', [redeemAmount], {from: redeemer}); +} + +contract('CEther', function ([root, minter, redeemer, ...accounts]) { + let cToken; + before(async () => { + cToken = await makeCToken({kind: 'cether', comptrollerOpts: {kind: 'bool'}}); + }); + + [mintExplicit, mintFallback].forEach((mint) => { + describe(mint.name, async () => { + beforeEach(async () => { + await preMint(cToken, minter, mintAmount, mintTokens, exchangeRate); + }); + + it("reverts if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + await assert.revertWithError(mint(cToken, minter, mintAmount), 'INTEREST_RATE_MODEL_ERROR', "revert mint failed"); + }); + + it("returns success from mintFresh and mints the correct number of tokens", async () => { + const beforeBalances = await getBalances([cToken], [minter]); + const receipt = await mint(cToken, minter, mintAmount); + const afterBalances = await getBalances([cToken], [minter]); + assert.success(receipt); + assert.numNotEqual(mintTokens, 0); + assert.deepEqual(afterBalances, await adjustBalances(beforeBalances, [ + [cToken, 'eth', mintAmount], + [cToken, 'tokens', mintTokens], + [cToken, minter, 'eth', -mintAmount.add(await etherGasCost(receipt))], + [cToken, minter, 'tokens', mintTokens] + ])); + }); + }); + }); + + [redeemCTokens, redeemUnderlying].forEach((redeem) => { + describe(redeem.name, async () => { + beforeEach(async () => { + await preRedeem(cToken, redeemer, redeemTokens, redeemAmount, exchangeRate); + }); + + it("emits a redeem failure if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + assert.hasTokenFailure( + await redeem(cToken, redeemer, redeemTokens, redeemAmount), + 'INTEREST_RATE_MODEL_ERROR', + 'REDEEM_ACCRUE_INTEREST_FAILED' + ); + }); + + it("returns error from redeemFresh without emitting any extra logs", async () => { + assert.hasTokenFailure( + await redeem(cToken, redeemer, redeemTokens.mul(5), redeemAmount.mul(5)), + 'MATH_ERROR', + 'REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED' + ); + }); + + it("returns success from redeemFresh and redeems the correct amount", async () => { + await fastForward(cToken); + const beforeBalances = await getBalances([cToken], [redeemer]); + const receipt = await redeem(cToken, redeemer, redeemTokens, redeemAmount); + const afterBalances = await getBalances([cToken], [redeemer]); + assert.success(receipt); + assert.numNotEqual(redeemTokens, 0); + assert.deepEqual(afterBalances, await adjustBalances(beforeBalances, [ + [cToken, 'eth', -redeemAmount], + [cToken, 'tokens', -redeemTokens], + [cToken, redeemer, 'eth', redeemAmount.sub(await etherGasCost(receipt))], + [cToken, redeemer, 'tokens', -redeemTokens] + ])); + }); + }); + }); +}); diff --git a/test/Tokens/mintAndRedeemTest.js b/test/Tokens/mintAndRedeemTest.js new file mode 100644 index 000000000..398c2e612 --- /dev/null +++ b/test/Tokens/mintAndRedeemTest.js @@ -0,0 +1,342 @@ +const { + etherUnsigned, + etherMantissa, + call, + send +} = require('../Utils/MochaTruffle'); + +const { + makeCToken, + balanceOf, + fastForward, + setBalance, + getBalances, + adjustBalances, + preApprove, + quickMint, + preSupply, + quickRedeem, + quickRedeemUnderlying +} = require('../Utils/Compound'); + +const exchangeRate = 50e3; +const mintAmount = etherUnsigned(10e4); +const mintTokens = mintAmount.div(exchangeRate); +const redeemTokens = etherUnsigned(10e3); +const redeemAmount = redeemTokens.mul(exchangeRate); + +async function preMint(cToken, minter, mintAmount, mintTokens, exchangeRate) { + await preApprove(cToken, minter, mintAmount); + await send(cToken.comptroller, 'setMintAllowed', [true]); + await send(cToken.comptroller, 'setMintVerify', [true]); + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + await send(cToken.underlying, 'harnessSetFailTransferFromAddress', [minter, false]); + await send(cToken, 'harnessSetBalance', [minter, 0]); + await send(cToken, 'harnessSetExchangeRate', [etherMantissa(exchangeRate)]); +} + +async function mintFresh(cToken, minter, mintAmount) { + return send(cToken, 'harnessMintFresh', [minter, mintAmount]); +} + +async function preRedeem(cToken, redeemer, redeemTokens, redeemAmount, exchangeRate) { + await preSupply(cToken, redeemer, redeemTokens); + await send(cToken.comptroller, 'setRedeemAllowed', [true]); + await send(cToken.comptroller, 'setRedeemVerify', [true]); + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + await send(cToken.underlying, 'harnessSetBalance', [cToken._address, redeemAmount]); + await send(cToken.underlying, 'harnessSetBalance', [redeemer, 0]); + await send(cToken.underlying, 'harnessSetFailTransferToAddress', [redeemer, false]); + await send(cToken, 'harnessSetExchangeRate', [etherMantissa(exchangeRate)]); +} + +async function redeemFreshTokens(cToken, redeemer, redeemTokens, redeemAmount) { + return send(cToken, 'harnessRedeemFresh', [redeemer, redeemTokens, 0]); +} + +async function redeemFreshAmount(cToken, redeemer, redeemTokens, redeemAmount) { + return send(cToken, 'harnessRedeemFresh', [redeemer, 0, redeemAmount]); +} + +contract('CToken', function ([root, minter, redeemer, ...accounts]) { + let cToken; + before(async () => { + cToken = await makeCToken({comptrollerOpts: {kind: 'bool'}, exchangeRate}); + }); + + describe('mintFresh', async () => { + beforeEach(async () => { + await preMint(cToken, minter, mintAmount, mintTokens, exchangeRate); + }); + + it("fails if comptroller tells it to", async () => { + await send(cToken.comptroller, 'setMintAllowed', [false]); + assert.hasTrollReject( + await mintFresh(cToken, minter, mintAmount), + 'MINT_COMPTROLLER_REJECTION', + 'MATH_ERROR' + ); + }); + + it("proceeds if comptroller tells it to", async () => { + await assert.success(await mintFresh(cToken, minter, mintAmount)); + }); + + it("fails if not fresh", async () => { + await fastForward(cToken); + assert.hasTokenFailure( + await mintFresh(cToken, minter, mintAmount), + 'MARKET_NOT_FRESH', + 'MINT_FRESHNESS_CHECK' + ); + }); + + it("continues if fresh", async () => { + await assert.succeeds(cToken, 'accrueInterest'); + assert.success(await mintFresh(cToken, minter, mintAmount)); + }); + + it("fails if insufficient approval", async () => { + assert.success(await send(cToken.underlying, 'approve', [cToken._address, 1], {from: minter})); + assert.hasTokenFailure( + await mintFresh(cToken, minter, mintAmount), + 'TOKEN_INSUFFICIENT_ALLOWANCE', + 'MINT_TRANSFER_IN_NOT_POSSIBLE' + ); + }); + + it("fails if insufficient balance", async() => { + await setBalance(cToken.underlying, minter, 1); + assert.hasTokenFailure( + await mintFresh(cToken, minter, mintAmount), + 'TOKEN_INSUFFICIENT_BALANCE', + 'MINT_TRANSFER_IN_NOT_POSSIBLE' + ); + }); + + it("proceeds if sufficient approval and balance", async () =>{ + assert.success(await mintFresh(cToken, minter, mintAmount)); + }); + + it("fails if exchange calculation fails", async () => { + assert.success(await send(cToken, 'harnessSetExchangeRate', [0])); + assert.hasTokenFailure( + await mintFresh(cToken, minter, mintAmount), + 'MATH_ERROR', + 'MINT_EXCHANGE_CALCULATION_FAILED' + ); + }); + + it("fails if transferring in fails", async () => { + await send(cToken.underlying, 'harnessSetFailTransferFromAddress', [minter, true]); + const result = await mintFresh(cToken, minter, mintAmount); + assert.hasTokenFailure( + result, + 'TOKEN_TRANSFER_IN_FAILED', + 'MINT_TRANSFER_IN_FAILED' + ); + }); + + it("transfers the underlying cash, tokens, and emits Mint, Transfer events", async () => { + const beforeBalances = await getBalances([cToken], [minter]); + const result = await mintFresh(cToken, minter, mintAmount); + const afterBalances = await getBalances([cToken], [minter]); + assert.success(result); + assert.hasLog(result, 'Mint', { + minter, + mintAmount: mintAmount.toString(), + mintTokens: mintTokens.toString() + }); + assert.hasLog(result, ['Transfer', 1], { + from: cToken._address, + to: minter, + amount: mintTokens.toString() + }); + assert.deepEqual(afterBalances, await adjustBalances(beforeBalances, [ + [cToken, minter, 'cash', -mintAmount], + [cToken, minter, 'tokens', mintTokens], + [cToken, 'cash', mintAmount], + [cToken, 'tokens', mintTokens] + ])); + }); + }); + + describe('mint', async () => { + beforeEach(async () => { + await preMint(cToken, minter, mintAmount, mintTokens, exchangeRate); + }); + + it("emits a mint failure if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + assert.hasTokenFailure( + await quickMint(cToken, minter, mintAmount), + 'INTEREST_RATE_MODEL_ERROR', + 'MINT_ACCRUE_INTEREST_FAILED' + ); + }); + + it("returns error from mintFresh without emitting any extra logs", async () => { + await send(cToken.underlying, 'harnessSetBalance', [minter, 1]); + assert.hasTokenFailure( + await quickMint(cToken, minter, mintAmount, {faucet: false}), + 'TOKEN_INSUFFICIENT_BALANCE', + 'MINT_TRANSFER_IN_NOT_POSSIBLE' + ); + }); + + it("returns success from mintFresh and mints the correct number of tokens", async () => { + assert.success(await quickMint(cToken, minter, mintAmount)); + assert.numNotEqual(mintTokens, 0); + assert.numEqual(await balanceOf(cToken, minter), mintTokens); + }); + + it("emits an AccrueInterest event", async () => { + assert.hasLog(await quickMint(cToken, minter, mintAmount), 'AccrueInterest', {}); + }); + }); + + [redeemFreshTokens, redeemFreshAmount].forEach((redeemFresh) => { + describe(redeemFresh.name, async () => { + beforeEach(async () => { + await preRedeem(cToken, redeemer, redeemTokens, redeemAmount, exchangeRate); + }); + + it("fails if comptroller tells it to", async () =>{ + await send(cToken.comptroller, 'setRedeemAllowed', [false]); + assert.hasTrollReject( + await redeemFresh(cToken, redeemer, redeemTokens, redeemAmount), + 'REDEEM_COMPTROLLER_REJECTION' + ); + }); + + it("fails if not fresh", async () => { + await fastForward(cToken); + assert.hasTokenFailure( + await redeemFresh(cToken, redeemer, redeemTokens, redeemAmount), + 'MARKET_NOT_FRESH', + 'REDEEM_FRESHNESS_CHECK' + ); + }); + + it("continues if fresh", async () => { + await assert.succeeds(cToken, 'accrueInterest'); + assert.success(await redeemFresh(cToken, redeemer, redeemTokens, redeemAmount)); + }); + + it("fails if insufficient protocol cash to transfer out", async() => { + await send(cToken.underlying, 'harnessSetBalance', [cToken._address, 1]); + assert.hasTokenFailure( + await redeemFresh(cToken, redeemer, redeemTokens, redeemAmount), + 'TOKEN_INSUFFICIENT_CASH', + 'REDEEM_TRANSFER_OUT_NOT_POSSIBLE' + ); + }); + + it("fails if exchange calculation fails", async () => { + if (redeemFresh == redeemFreshTokens) { + assert.success(await send(cToken, 'harnessSetExchangeRate', [-1])); + assert.hasTokenFailure( + await redeemFresh(cToken, redeemer, redeemTokens, redeemAmount), + 'MATH_ERROR', + 'REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED' + ); + } else { + assert.success(await send(cToken, 'harnessSetExchangeRate', [0])); + assert.hasTokenFailure( + await redeemFresh(cToken, redeemer, redeemTokens, redeemAmount), + 'MATH_ERROR', + 'REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED' + ); + } + }); + + it("fails if transferring out fails", async () => { + await send(cToken.underlying, 'harnessSetFailTransferToAddress', [redeemer, true]); + await assert.revert(redeemFresh(cToken, redeemer, redeemTokens, redeemAmount), "revert redeem transfer out failed"); + }); + + it("fails if total supply < redemption amount", async () => { + await send(cToken, 'harnessExchangeRateDetails', [0, 0, 0]); + assert.hasTokenFailure( + await redeemFresh(cToken, redeemer, redeemTokens, redeemAmount), + 'MATH_ERROR', + 'REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED' + ); + }); + + it("reverts if new account balance underflows", async () => { + await send(cToken, 'harnessSetBalance', [redeemer, 0]); + assert.hasTokenFailure( + await redeemFresh(cToken, redeemer, redeemTokens, redeemAmount), + 'MATH_ERROR', + 'REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED' + ); + }); + + it("transfers the underlying cash, tokens, and emits Redeem, Transfer events", async () => { + const beforeBalances = await getBalances([cToken], [redeemer]); + const result = await redeemFresh(cToken, redeemer, redeemTokens, redeemAmount); + const afterBalances = await getBalances([cToken], [redeemer]); + assert.success(result); + assert.hasLog(result, 'Redeem', { + redeemer, + redeemAmount: redeemAmount.toString(), + redeemTokens: redeemTokens.toString() + }); + assert.hasLog(result, ['Transfer', 1], { + from: redeemer, + to: cToken._address, + amount: redeemTokens.toString() + }); + assert.deepEqual(afterBalances, await adjustBalances(beforeBalances, [ + [cToken, redeemer, 'cash', redeemAmount], + [cToken, redeemer, 'tokens', -redeemTokens], + [cToken, 'cash', -redeemAmount], + [cToken, 'tokens', -redeemTokens] + ])); + }); + }); + }); + + describe('redeem', async () => { + beforeEach(async () => { + await preRedeem(cToken, redeemer, redeemTokens, redeemAmount, exchangeRate); + }); + + it("emits a redeem failure if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + assert.hasTokenFailure( + await quickRedeem(cToken, redeemer, redeemTokens), + 'INTEREST_RATE_MODEL_ERROR', + 'REDEEM_ACCRUE_INTEREST_FAILED' + ); + }); + + it("returns error from redeemFresh without emitting any extra logs", async () => { + await setBalance(cToken.underlying, cToken._address, 0); + assert.hasTokenFailure( + await quickRedeem(cToken, redeemer, redeemTokens, {exchangeRate}), + 'TOKEN_INSUFFICIENT_CASH', + 'REDEEM_TRANSFER_OUT_NOT_POSSIBLE' + ); + }); + + it("returns success from redeemFresh and redeems the right amount", async () => { + assert.success(await send(cToken.underlying, 'harnessSetBalance', [cToken._address, redeemAmount])); + assert.success(await quickRedeem(cToken, redeemer, redeemTokens, {exchangeRate})); + assert.numNotEqual(redeemAmount, 0); + assert.numEqual(await balanceOf(cToken.underlying, redeemer), redeemAmount); + }); + + it("returns success from redeemFresh and redeems the right amount of underlying", async () => { + assert.success(await send(cToken.underlying, 'harnessSetBalance', [cToken._address, redeemAmount])); + assert.success(await quickRedeemUnderlying(cToken, redeemer, redeemAmount, {exchangeRate})); + assert.numNotEqual(redeemAmount, 0); + assert.numEqual(await balanceOf(cToken.underlying, redeemer), redeemAmount); + }); + + it("emits an AccrueInterest event", async () => { + assert.hasLog(await quickMint(cToken, minter, mintAmount), 'AccrueInterest', {}); + }); + }); +}); diff --git a/test/Tokens/reservesTest.js b/test/Tokens/reservesTest.js new file mode 100644 index 000000000..4c77a21d5 --- /dev/null +++ b/test/Tokens/reservesTest.js @@ -0,0 +1,209 @@ +const { + etherUnsigned, + etherMantissa, + both, + call, + send +} = require('../Utils/MochaTruffle'); + +const {makeCToken} = require('../Utils/Compound'); + +const factor = etherMantissa(.02); + +const reserves = etherUnsigned(3e12); +const cash = etherUnsigned(reserves.mul(2)); +const reduction = etherUnsigned(2e12); + +contract('CToken', function ([root, ...accounts]) { + describe('_setReserveFactorFresh', async () => { + let cToken; + beforeEach(async () => { + cToken = await makeCToken(); + }); + + it("rejects change by non-admin", async () => { + assert.hasTokenFailure( + await send(cToken, 'harnessSetReserveFactorFresh', [factor], {from: accounts[0]}), + 'UNAUTHORIZED', + 'SET_RESERVE_FACTOR_ADMIN_CHECK' + ); + assert.equal(await call(cToken, 'reserveFactorMantissa'), 0, "reserve factor should still be 0"); + }); + + it("rejects change if market not fresh", async () => { + assert.success(await send(cToken, 'harnessFastForward', [5])); + assert.hasTokenFailure( + await send(cToken, 'harnessSetReserveFactorFresh', [factor]), + 'MARKET_NOT_FRESH', + 'SET_RESERVE_FACTOR_FRESH_CHECK' + ); + assert.equal(await call(cToken, 'reserveFactorMantissa'), 0, "reserve factor should still be 0"); + }); + + it("rejects newReserveFactor that descales to 1", async () => { + assert.hasTokenFailure( + await send(cToken, 'harnessSetReserveFactorFresh', [etherMantissa(1.01)]), + 'BAD_INPUT', + 'SET_RESERVE_FACTOR_BOUNDS_CHECK' + ); + assert.equal(await call(cToken, 'reserveFactorMantissa'), 0, "reserve factor should still be 0"); + }); + + it("accepts newReserveFactor in valid range and emits log", async () => { + const result = await send(cToken, 'harnessSetReserveFactorFresh', [factor]) + assert.success(result); + assert.equal(await call(cToken, 'reserveFactorMantissa'), factor, "reserve factor should be updated"); + assert.hasLog(result, "NewReserveFactor", { + oldReserveFactorMantissa: '0', + newReserveFactorMantissa: factor.toString(), + }); + }); + + it("accepts a change back to zero", async () => { + const result1 = await send(cToken, 'harnessSetReserveFactorFresh', [factor]); + const result2 = await send(cToken, 'harnessSetReserveFactorFresh', [0]); + assert.success(result1); + assert.success(result2); + assert.hasLog(result2, "NewReserveFactor", { + oldReserveFactorMantissa: factor.toString(), + newReserveFactorMantissa: '0', + }); + assert.equal(await call(cToken, 'reserveFactorMantissa'), 0, "reserve factor should still be 0"); + }); + }); + + describe('_setReserveFactor', async () => { + let cToken; + before(async () => { + cToken = await makeCToken(); + }); + + beforeEach(async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + await send(cToken, '_setReserveFactor', [0]); + }); + + it("emits a reserve factor failure if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + assert.hasTokenFailure( + await send(cToken, '_setReserveFactor', [factor]), + 'INTEREST_RATE_MODEL_ERROR', + 'SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED' + ); + assert.equal(await call(cToken, 'reserveFactorMantissa'), 0, "reserve factor should be 0"); + }); + + it("returns error from setReserveFactorFresh without emitting any extra logs", async () => { + const {reply, receipt} = await both(cToken, '_setReserveFactor', [etherMantissa(2)]); + assert.hasError(reply, 'BAD_INPUT'); + assert.hasTokenFailure( + receipt, + 'BAD_INPUT', + 'SET_RESERVE_FACTOR_BOUNDS_CHECK' + ); + assert.equal(await call(cToken, 'reserveFactorMantissa'), 0, "reserve factor should be 0"); + }); + + it("returns success from setReserveFactorFresh", async () => { + assert.equal(await call(cToken, 'reserveFactorMantissa'), 0, "reserve factor begin as 0"); + assert.success(await send(cToken, 'harnessFastForward', [5])); + await assert.succeeds(cToken, '_setReserveFactor', [factor]); + assert.equal(await call(cToken, 'reserveFactorMantissa'), factor, "reserve factor should be updated"); + }); + }); + + describe("_reduceReservesFresh", async () => { + let cToken; + beforeEach(async () => { + cToken = await makeCToken(); + assert.success(await send(cToken, 'harnessSetTotalReserves', [reserves])); + assert.success(await send(cToken.underlying, 'harnessSetBalance', [cToken._address, cash])); + }); + + it("fails if called by non-admin", async () => { + assert.hasTokenFailure( + await send(cToken, 'harnessReduceReservesFresh', [reduction], {from: accounts[0]}), + 'UNAUTHORIZED', + 'REDUCE_RESERVES_ADMIN_CHECK' + ); + assert.equal(await call(cToken, 'totalReserves'), reserves, "reserves should not have changed"); + }); + + it("fails if market not fresh", async () => { + assert.success(await send(cToken, 'harnessFastForward', [5])); + assert.hasTokenFailure( + await send(cToken, 'harnessReduceReservesFresh', [reduction]), + 'MARKET_NOT_FRESH', + 'REDUCE_RESERVES_FRESH_CHECK' + ); + assert.equal(await call(cToken, 'totalReserves'), reserves, "reserves should not have changed"); + }); + + it("fails if amount exceeds reserves", async () => { + assert.hasTokenFailure( + await send(cToken, 'harnessReduceReservesFresh', [reserves.add(1)]), + 'BAD_INPUT', + 'REDUCE_RESERVES_VALIDATION' + ); + assert.equal(await call(cToken, 'totalReserves'), reserves, "reserves should not have changed"); + }); + + it("fails if amount exceeds available cash", async () => { + const cashLessThanReserves = reserves.sub(2); + await send(cToken.underlying, 'harnessSetBalance', [cToken._address, cashLessThanReserves]); + assert.hasTokenFailure( + await send(cToken, 'harnessReduceReservesFresh', [reserves]), + 'TOKEN_INSUFFICIENT_CASH', + 'REDUCE_RESERVES_CASH_NOT_AVAILABLE' + ); + assert.equal(await call(cToken, 'totalReserves'), reserves, "reserves should not have changed"); + }); + + it("increases admin balance and reduces reserves on success", async () => { + const balance = etherUnsigned(await call(cToken.underlying, 'balanceOf', [root])); + assert.success(await send(cToken, 'harnessReduceReservesFresh', [reserves])); + assert.equal(await call(cToken.underlying, 'balanceOf', [root]), balance.add(reserves), "admin balance should have increased"); + assert.equal(await call(cToken, 'totalReserves'), 0, "reserves should have decreased"); + }); + + it("emits an event on success", async () => { + const result = await send(cToken, 'harnessReduceReservesFresh', [reserves]); + assert.hasLog(result, 'ReservesReduced', { + admin: root, + reduceAmount: reserves.toString(), + newTotalReserves: '0' + }); + }); + }); + + describe("_reduceReserves", async () => { + let cToken; + beforeEach(async () => { + cToken = await makeCToken(); + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + assert.success(await send(cToken, 'harnessSetTotalReserves', [reserves])); + assert.success(await send(cToken.underlying, 'harnessSetBalance', [cToken._address, cash])); + }); + + it("emits a reserve-reduction failure if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + assert.hasTokenFailure( + await send(cToken, '_reduceReserves', [reduction]), + 'INTEREST_RATE_MODEL_ERROR', + 'REDUCE_RESERVES_ACCRUE_INTEREST_FAILED' + ); + }); + + it("returns error from _reduceReservesFresh without emitting any extra logs", async () => { + const {reply, receipt} = await both(cToken, 'harnessReduceReservesFresh', [reserves.add(1)]); + assert.hasTokenError(reply, 'BAD_INPUT'); + assert.hasTokenFailure(receipt, 'BAD_INPUT', 'REDUCE_RESERVES_VALIDATION'); + }); + + it("returns success code from _reduceReservesFresh and reduces the correct amount", async () => { + assert.equal(await call(cToken, 'totalReserves'), reserves); + assert.success(await send(cToken, 'harnessFastForward', [5])); + await assert.succeeds(cToken, '_reduceReserves', [reduction]); + }); + }); +}); \ No newline at end of file diff --git a/test/Tokens/safeTokenTest.js b/test/Tokens/safeTokenTest.js new file mode 100644 index 000000000..d1f1736f2 --- /dev/null +++ b/test/Tokens/safeTokenTest.js @@ -0,0 +1,69 @@ +const { + call, + send +} = require('../Utils/MochaTruffle'); + +const { + makeCToken, + getBalances, + adjustBalances +} = require('../Utils/Compound'); + +const exchangeRate = 5; + +contract('CEther', function ([root, nonRoot, ...accounts]) { + let cToken; + before(async () => { + cToken = await makeCToken({kind: 'cether', comptrollerOpts: {kind: 'bool'}}); + }); + + describe("getCashPrior", async () => { + it("returns the amount of ether held by the cEther contract before the current message", async () => { + assert.equal(await call(cToken, 'harnessGetCashPrior', [], {value: 100}), 0); + }); + }); + + describe("doTransferIn", async () => { + it("succeeds if from is msg.nonRoot and amount is msg.value", async () => { + assert.equal(await call(cToken, 'harnessDoTransferIn', [root, 100], {value: 100}), 0); + }); + + it("reverts if from != msg.sender", async () => { + await assert.revert(call(cToken, 'harnessDoTransferIn', [nonRoot, 100], {value: 100}), "revert sender mismatch"); + }); + + it("reverts if amount != msg.value", async () => { + await assert.revert(call(cToken, 'harnessDoTransferIn', [root, 77], {value: 100}), "revert value mismatch"); + }); + + describe("doTransferOut", async () => { + it("transfers ether out", async () => { + const beforeBalances = await getBalances([cToken], [nonRoot]); + const receipt = await send(cToken, 'harnessDoTransferOut', [nonRoot, 77], {value: 77}); + const afterBalances = await getBalances([cToken], [nonRoot]); + assert.success(receipt); + assert.deepEqual(afterBalances, await adjustBalances(beforeBalances, [ + [cToken, nonRoot, 'eth', 77] + ])); + }); + + it("reverts if it fails", async () => { + await assert.revert(call(cToken, 'harnessDoTransferOut', [root, 77], {value: 0})); + }); + }); + + describe("checkTransferIn", async () => { + it("succeeds", async () => { + assert.hasError(await call(cToken, 'harnessCheckTransferIn', [root, 100], {value: 100}), 'NO_ERROR'); + }); + + it("reverts if sender is not from", async () => { + await assert.revert(call(cToken, 'harnessCheckTransferIn', [nonRoot, 100], {value: 100}), "revert sender mismatch"); + }); + + it("reverts if amount is not msg.value", async () => { + await assert.revert(call(cToken, 'harnessCheckTransferIn', [root, 77], {value: 100}), "revert value mismatch"); + }); + }); + }); +}); diff --git a/test/Tokens/setComptrollerTest.js b/test/Tokens/setComptrollerTest.js new file mode 100644 index 000000000..3939185aa --- /dev/null +++ b/test/Tokens/setComptrollerTest.js @@ -0,0 +1,48 @@ +const {call, send} = require('../Utils/MochaTruffle'); +const { + makeComptroller, + makeCToken +} = require('../Utils/Compound'); + +contract('CToken', function([root, ...accounts]) { + let cToken, oldComptroller, newComptroller; + before(async () => { + cToken = await makeCToken(); + oldComptroller = cToken.comptroller; + newComptroller = await makeComptroller(); + assert.notEqual(newComptroller._address, oldComptroller._address, 'setup failed'); + }); + + describe('_setComptroller', async () => { + it("should fail if called by non-admin", async () => { + assert.hasTokenFailure( + await send(cToken, '_setComptroller', [newComptroller._address], {from: accounts[0]}), + 'UNAUTHORIZED', + 'SET_COMPTROLLER_OWNER_CHECK' + ); + assert.equal(await call(cToken, 'comptroller'), oldComptroller._address); + }); + + it("reverts if passed a contract that doesn't implement isComptroller", async () => { + await assert.revert(send(cToken, '_setComptroller', [cToken.underlying._address])); + assert.equal(await call(cToken, 'comptroller'), oldComptroller._address); + }); + + it("reverts if passed a contract that implements isComptroller as false", async () => { + // extremely unlikely to occur, of course, but let's be exhaustive + const badComptroller = await makeComptroller({kind: 'false-marker'}); + await assert.revert(send(cToken, '_setComptroller', [badComptroller._address]), "revert marker method returned false"); + assert.equal(await call(cToken, 'comptroller'), oldComptroller._address); + }); + + it("updates comptroller and emits log on success", async () => { + const result = await send(cToken, '_setComptroller', [newComptroller._address]); + assert.success(result); + assert.hasLog(result, 'NewComptroller', { + oldComptroller: oldComptroller._address, + newComptroller: newComptroller._address + }); + assert.equal(await call(cToken, 'comptroller'), newComptroller._address); + }); + }); +}); diff --git a/test/Tokens/setInterestRateModelTest.js b/test/Tokens/setInterestRateModelTest.js new file mode 100644 index 000000000..905431d74 --- /dev/null +++ b/test/Tokens/setInterestRateModelTest.js @@ -0,0 +1,103 @@ +const {both, call, send} = require('../Utils/MochaTruffle'); +const { + makeCToken, + makeInterestRateModel +} = require('../Utils/Compound'); + +contract('CToken', function ([root, ...accounts]) { + let newModel; + before(async () => { + newModel = await makeInterestRateModel(); + }); + + describe("_setInterestRateModelFresh", async () => { + let cToken, oldModel; + beforeEach(async () => { + cToken = await makeCToken(); + oldModel = cToken.interestRateModel; + assert.notEqual(oldModel._address, newModel._address, 'setup failed'); + }); + + it("fails if called by non-admin", async () => { + assert.hasTokenFailure( + await send(cToken, 'harnessSetInterestRateModelFresh', [newModel._address], {from: accounts[0]}), + 'UNAUTHORIZED', + 'SET_INTEREST_RATE_MODEL_OWNER_CHECK' + ); + assert.equal(await call(cToken, 'interestRateModel'), oldModel._address); + }); + + it("fails if market not fresh", async () => { + assert.success(await send(cToken, 'harnessFastForward', [5])); + assert.hasTokenFailure( + await send(cToken, 'harnessSetInterestRateModelFresh', [newModel._address]), + 'MARKET_NOT_FRESH', + 'SET_INTEREST_RATE_MODEL_FRESH_CHECK' + ); + assert.equal(await call(cToken, 'interestRateModel'), oldModel._address); + }); + + it("reverts if passed a contract that doesn't implement isInterestRateModel", async () => { + await assert.revert(send(cToken, 'harnessSetInterestRateModelFresh', [cToken.underlying._address])); + assert.equal(await call(cToken, 'interestRateModel'), oldModel._address); + }); + + it("reverts if passed a contract that implements isInterestRateModel as false", async () => { + // extremely unlikely to occur, of course, but let's be exhaustive + const badModel = await makeInterestRateModel({kind: 'false-marker'}); + await assert.revert(send(cToken, 'harnessSetInterestRateModelFresh', [badModel._address]), "revert marker method returned false"); + assert.equal(await call(cToken, 'interestRateModel'), oldModel._address); + }); + + it("accepts new valid interest rate model", async () => { + assert.success(await send(cToken, 'harnessSetInterestRateModelFresh', [newModel._address])); + assert.equal(await call(cToken, 'interestRateModel'), newModel._address); + }); + + it("emits expected log when accepting a new valid interest rate model", async () => { + const result = await send(cToken, 'harnessSetInterestRateModelFresh', [newModel._address]); + assert.success(result); + assert.hasLog(result, 'NewMarketInterestRateModel', { + oldInterestRateModel: oldModel._address, + newInterestRateModel: newModel._address, + }); + assert.equal(await call(cToken, 'interestRateModel'), newModel._address); + }); + }); + + describe("_setInterestRateModel", async () => { + let cToken; + before(async () => { + cToken = await makeCToken(); + }); + + beforeEach(async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [false]); + }); + + it("emits a set market interest rate model failure if interest accrual fails", async () => { + await send(cToken.interestRateModel, 'setFailBorrowRate', [true]); + assert.hasTokenFailure( + await send(cToken, '_setInterestRateModel', [newModel._address]), + 'INTEREST_RATE_MODEL_ERROR', + 'SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED' + ); + }); + + it("returns error from _setInterestRateModelFresh without emitting any extra logs", async () => { + const {reply, receipt} = await both(cToken, '_setInterestRateModel', [newModel._address], {from: accounts[0]}); + assert.hasError(reply, 'UNAUTHORIZED'); + assert.hasTokenFailure(receipt, + 'UNAUTHORIZED', + 'SET_INTEREST_RATE_MODEL_OWNER_CHECK' + ); + }); + + it("reports success when _setInterestRateModelFresh succeeds", async () => { + const {reply, receipt} = await both(cToken, '_setInterestRateModel', [newModel._address]); + assert.equal(reply, 0, "return code should be 0"); + assert.success(receipt); + assert.equal(await call(cToken, 'interestRateModel'), newModel._address); + }); + }); +}); \ No newline at end of file diff --git a/test/Tokens/transferTest.js b/test/Tokens/transferTest.js new file mode 100644 index 000000000..cbdb90276 --- /dev/null +++ b/test/Tokens/transferTest.js @@ -0,0 +1,52 @@ +const {call, send} = require('../Utils/MochaTruffle'); +const {makeCToken} = require('../Utils/Compound'); + +contract('CToken', function ([root, ...accounts]) { + describe('transfer', () => { + it("cannot transfer from a zero balance", async () => { + const cToken = await makeCToken({supportMarket: true}); + assert.equal(await call(cToken, 'balanceOf', [root]), 0); + assert.hasTokenFailure( + await send(cToken, 'transfer', [accounts[0], 100]), + 'MATH_ERROR', + 'TRANSFER_NOT_ENOUGH' + ); + }); + + it("transfers 50 tokens", async () => { + const cToken = await makeCToken({supportMarket: true}); + await send(cToken, 'harnessSetBalance', [root, 100]); + assert.equal(await call(cToken, 'balanceOf', [root]), 100); + await send(cToken, 'transfer', [accounts[0], 50]); + assert.equal(await call(cToken, 'balanceOf', [root]), 50); + assert.equal(await call(cToken, 'balanceOf', [accounts[0]]), 50); + }); + + it("doesn't transfer when src == dst", async () => { + const cToken = await makeCToken({supportMarket: true}); + await send(cToken, 'harnessSetBalance', [root, 100]); + assert.equal(await call(cToken, 'balanceOf', [root]), 100); + assert.hasTokenFailure( + await send(cToken, 'transfer', [root, 50]), + 'BAD_INPUT', + 'TRANSFER_NOT_ALLOWED' + ); + }); + + it("rejects transfer when not allowed and reverts if not verified", async () => { + const cToken = await makeCToken({comptrollerOpts: {kind: 'bool'}}); + await send(cToken, 'harnessSetBalance', [root, 100]); + assert.equal(await call(cToken, 'balanceOf', [root]), 100); + + await send(cToken.comptroller, 'setTransferAllowed', [false]) + assert.hasTrollReject( + await send(cToken, 'transfer', [root, 50]), + 'TRANSFER_COMPTROLLER_REJECTION' + ); + + await send(cToken.comptroller, 'setTransferAllowed', [true]) + await send(cToken.comptroller, 'setTransferVerify', [false]) + await assert.revert(send(cToken, 'transfer', [accounts[0], 50]), "revert transferVerify rejected transfer"); + }); + }); +}); \ No newline at end of file diff --git a/test/Utils/Compound.js b/test/Utils/Compound.js new file mode 100644 index 000000000..e15ea5cae --- /dev/null +++ b/test/Utils/Compound.js @@ -0,0 +1,378 @@ +"use strict"; + +const {dfn} = require('./JS'); +const { + etherBalance, + etherMantissa, + etherUnsigned, + + getContract, + getTestContract, + guessRoot, + + send, + call, + callUnsigned +} = require('./MochaTruffle'); + +async function makeComptroller(opts = {}) { + const { + root = await guessRoot(), + kind = 'unitroller-v1' + } = opts || {}; + + if (kind == 'bool') { + const Comptroller = getTestContract('BoolComptroller'); + const comptroller = await Comptroller.deploy().send({from: root}); + return comptroller; + } + + if (kind == 'false-marker') { + const Comptroller = getTestContract('FalseMarkerMethodComptroller'); + const comptroller = await Comptroller.deploy().send({from: root}); + return comptroller; + } + + if (kind == 'v1-no-proxy' ) { + const Comptroller = getContract('ComptrollerHarness'); + const priceOracle = opts.priceOracle || await makePriceOracle(opts.priceOracleOpts); + const closeFactor = etherMantissa(dfn(opts.closeFactor, .051)); + const maxAssets = etherUnsigned(dfn(opts.maxAssets, 10)); + const liquidationIncentive = etherUnsigned(1); + const comptroller = await Comptroller.deploy().send({from: root}); + + await comptroller.methods._setLiquidationIncentive(liquidationIncentive).send({from: root}); + await comptroller.methods._setCloseFactor(closeFactor).send({from: root}); + await comptroller.methods._setMaxAssets(maxAssets).send({from: root}); + await comptroller.methods._setPriceOracle(priceOracle._address).send({from: root}); + + comptroller.options.address = comptroller._address; + return Object.assign(comptroller, {priceOracle}); + } + + if (kind == 'unitroller-v1') { + const Unitroller = getContract('Unitroller'); + const Comptroller = getContract('ComptrollerHarness'); + const priceOracle = opts.priceOracle || await makePriceOracle(opts.priceOracleOpts); + const closeFactor = etherMantissa(dfn(opts.closeFactor, .051)); + const maxAssets = etherUnsigned(dfn(opts.maxAssets, 10)); + const unitroller = await Unitroller.deploy().send({from: root}); + const comptroller = await Comptroller.deploy().send({from: root}); + await unitroller.methods._setPendingImplementation(comptroller._address).send({from: root}); + await comptroller.methods._become(unitroller._address, priceOracle._address, closeFactor, maxAssets, false).send({from: root}); + comptroller.options.address = unitroller._address; + return Object.assign(comptroller, {priceOracle}); + } +} + +async function makeCToken(opts = {}) { + const { + root = await guessRoot(), + kind = 'cerc20' + } = opts || {}; + + const comptroller = opts.comptroller || await makeComptroller(opts.comptrollerOpts); + const interestRateModel = opts.interestRateModel || await makeInterestRateModel(opts.interestRateModelOpts); + const exchangeRate = etherMantissa(dfn(opts.exchangeRate, 1)); + const decimals = etherUnsigned(dfn(opts.decimals, 8)); + const symbol = opts.symbol || 'cOMG'; + const name = opts.name || `CToken ${symbol}`; + + let cToken, underlying; + + switch (kind) { + case 'cether': + const CEther = getTestContract('CEtherHarness'); + cToken = await CEther.deploy({ + arguments: [ + comptroller._address, + interestRateModel._address, + exchangeRate, + name, + symbol, + decimals + ]}).send({from: root}); + break; + case 'cerc20': + default: + const CErc20 = getTestContract('CErc20Harness'); + underlying = opts.underlying || await makeToken(opts.underlyingOpts); + cToken = await CErc20.deploy({ + arguments: [ + underlying._address, + comptroller._address, + interestRateModel._address, + exchangeRate, + name, + symbol, + decimals + ]}).send({from: root}); + break; + } + + if (opts.supportMarket) { + await comptroller.methods._supportMarket(cToken._address).send({from: root}); + } + + if (opts.underlyingPrice) { + const price = etherMantissa(opts.underlyingPrice); + await comptroller.priceOracle.methods.setUnderlyingPrice(cToken._address, price).send({from: root}); + } + + if (opts.collateralFactor) { + const factor = etherMantissa(opts.collateralFactor); + await comptroller.methods._setCollateralFactor(cToken._address, factor).send({from: root}); + } + + return Object.assign(cToken, {name, symbol, underlying, comptroller, interestRateModel}); +} + +async function makeInterestRateModel(opts = {}) { + const { + root = await guessRoot(), + kind = 'harnessed' + } = opts || {}; + + if (kind == 'harnessed') { + const InterestRateModel = getTestContract('InterestRateModelHarness'); + const borrowRate = etherMantissa(dfn(opts.borrowRate, 0)); + const interestRateModel = await InterestRateModel.deploy({arguments: [borrowRate]}).send({from: root}); + return interestRateModel; + } + + if (kind == 'false-marker') { + const InterestRateModel = getTestContract('FalseMarkerMethodInterestRateModel'); + const borrowRate = etherMantissa(dfn(opts.borrowRate, 0)); + const interestRateModel = await InterestRateModel.deploy({arguments: [borrowRate]}).send({from: root}); + return interestRateModel; + } + + if (kind == 'white-paper') { + const InterestRateModel = getTestContract('WhitePaperInterestRateModel'); + const baseRate = etherMantissa(dfn(opts.baseRate, 0)); + const multiplier = etherMantissa(dfn(opts.multiplier, 1e-18)); + const interestRateModel = await InterestRateModel.deploy({arguments: [baseRate, multiplier]}).send({from: root}); + return interestRateModel; + } +} + +async function makePriceOracle(opts = {}) { + const { + root = await guessRoot(), + kind = 'simple' + } = opts || {}; + + if (kind == 'simple') { + const PriceOracle = getContract('SimplePriceOracle'); + const priceOracle = await PriceOracle.deploy().send({from: root}); + return priceOracle; + } + + if (kind == 'proxy') { + const cEther = opts.cEther || await makeCToken({ + kind: 'cether', + supportMarket: true, + comptrollerOpts: { + priceOracleOpts: {kind: 'simple'} + }, ...opts.cEtherOpts}); + const comptroller = cEther.comptroller; + const priceOracle = comptroller.priceOracle; + const PriceOracleProxy = getContract('PriceOracleProxy'); + const priceOracleProxy = await PriceOracleProxy.deploy({ + arguments: [ + comptroller._address, + priceOracle._address, + cEther._address + ]}).send({from: root}); + return Object.assign(priceOracleProxy, {cEther, comptroller, priceOracle}); + } +} + +async function makeToken(opts = {}) { + const { + root = await guessRoot(), + kind = 'erc20' + } = opts || {}; + + if (kind == 'erc20') { + const Token = getTestContract('EIP20Harness'); + const quantity = etherUnsigned(dfn(opts.quantity, 1e25)); + const decimals = etherUnsigned(dfn(opts.decimals, 18)); + const symbol = opts.symbol || 'OMG'; + const name = opts.name || `Erc20 ${symbol}`; + const token = await Token.deploy({arguments: [quantity, name, decimals, symbol]}).send({from: root}); + return token; + } +} + +async function balanceOf(token, account) { + return callUnsigned(token, 'balanceOf', [account]); +} + +async function totalSupply(token) { + return callUnsigned(token, 'totalSupply'); +} + +async function borrowSnapshot(cToken, account) { + const {principal, interestIndex} = await call(cToken, 'harnessAccountBorrows', [account]); + return {principal: etherUnsigned(principal), interestIndex: etherUnsigned(interestIndex)}; +} + +async function totalBorrows(cToken) { + return callUnsigned(cToken, 'totalBorrows'); +} + +async function totalReserves(cToken) { + return callUnsigned(cToken, 'totalReserves'); +} + +async function enterMarkets(cTokens, from) { + return send(cTokens[0].comptroller, 'enterMarkets', [cTokens.map(c => c._address)], {from}); +} + +async function fastForward(cToken, blocks = 5) { + return send(cToken, 'harnessFastForward', [blocks]); +} + +async function setBalance(cToken, account, balance) { + return send(cToken, 'harnessSetBalance', [account, balance]); +} + +async function setEtherBalance(cEther, balance) { + const current = await etherBalance(cEther._address); + const root = await guessRoot(); + await send(cEther, 'harnessDoTransferOut', [root, current]); + await send(cEther, 'harnessDoTransferIn', [root, balance], {value: balance}); +} + +async function getBalances(cTokens, accounts) { + const balances = {}; + for (let cToken of cTokens) { + const cBalances = balances[cToken._address] = {}; + for (let account of accounts) { + cBalances[account] = { + eth: await etherBalance(account), + cash: cToken.underlying && await balanceOf(cToken.underlying, account), + tokens: await balanceOf(cToken, account), + borrows: (await borrowSnapshot(cToken, account)).principal + }; + } + cBalances[cToken._address] = { + eth: await etherBalance(cToken._address), + cash: cToken.underlying && await balanceOf(cToken.underlying, cToken._address), + tokens: await totalSupply(cToken), + borrows: await totalBorrows(cToken), + reserves: await totalReserves(cToken) + }; + } + return balances; +} + +async function adjustBalances(balances, deltas) { + for (let delta of deltas) { + let cToken, account, key, diff; + if (delta.length == 4) { + ([cToken, account, key, diff] = delta); + } else { + ([cToken, key, diff] = delta); + account = cToken._address; + } + balances[cToken._address][account][key] = balances[cToken._address][account][key].add(diff); + } + return balances; +} + + +async function preApprove(cToken, from, amount, opts = {}) { + if (dfn(opts.faucet, true)){ + assert.success(await send(cToken.underlying, 'harnessSetBalance', [from, amount], {from})); + } + return send(cToken.underlying, 'approve', [cToken._address, amount], {from}); +} + +async function quickMint(cToken, minter, mintAmount, opts = {}) { + if (dfn(opts.approve, true)){ + assert.success(await preApprove(cToken, minter, mintAmount, opts)); + } + if (dfn(opts.exchangeRate)){ + assert.success(await send(cToken, 'harnessSetExchangeRate', [etherMantissa(opts.exchangeRate)])); + } + return send(cToken, 'mint', [mintAmount], {from: minter}); +} + + +async function preSupply(cToken, account, tokens, opts = {}) { + if (dfn(opts.total, true)){ + assert.success(await send(cToken, 'harnessSetTotalSupply', [tokens])); + } + return send(cToken, 'harnessSetBalance', [account, tokens]); +} + +async function quickRedeem(cToken, redeemer, redeemTokens, opts = {}) { + if (dfn(opts.supply, true)) { + assert.success(await preSupply(cToken, redeemer, redeemTokens, opts)); + } + if (dfn(opts.exchangeRate)) { + assert.success(await send(cToken, 'harnessSetExchangeRate', [etherMantissa(opts.exchangeRate)])); + } + return send(cToken, 'redeem', [redeemTokens], {from: redeemer}); +} + +async function quickRedeemUnderlying(cToken, redeemer, redeemAmount, opts = {}) { + if (dfn(opts.exchangeRate)){ + assert.success(await send(cToken, 'harnessSetExchangeRate', [etherMantissa(opts.exchangeRate)])); + } + return send(cToken, 'redeemUnderlying', [redeemAmount], {from: redeemer}); +} + +async function setOraclePrice(cToken, price) { + return send(cToken.comptroller.priceOracle, 'setUnderlyingPrice', [cToken._address, etherMantissa(price)]); +} + +async function setBorrowRate(cToken, rate) { + return send(cToken.interestRateModel, 'setBorrowRate', [etherMantissa(rate)]); +} + +async function getBorrowRate(interestRateModel, cash, borrows, reserves) { + return call(interestRateModel, 'getBorrowRate', [cash, borrows, reserves].map(etherUnsigned)); +} + +async function pretendBorrow(cToken, borrower, accountIndex, marketIndex, principalRaw, blockNumber = 2e7) { + await send(cToken, 'harnessSetTotalBorrows', [etherUnsigned(principalRaw)]); + await send(cToken, 'harnessSetAccountBorrows', [borrower, etherUnsigned(principalRaw), etherMantissa(accountIndex)]); + await send(cToken, 'harnessSetBorrowIndex', [etherMantissa(marketIndex)]); + await send(cToken, 'harnessSetAccrualBlockNumber', [etherUnsigned(blockNumber)]); + await send(cToken, 'harnessSetBlockNumber', [etherUnsigned(blockNumber)]); +} + +module.exports = { + makeComptroller, + makeCToken, + makeInterestRateModel, + makePriceOracle, + makeToken, + + balanceOf, + totalSupply, + borrowSnapshot, + totalBorrows, + totalReserves, + enterMarkets, + fastForward, + setBalance, + setEtherBalance, + getBalances, + adjustBalances, + + preApprove, + quickMint, + + preSupply, + quickRedeem, + quickRedeemUnderlying, + + setOraclePrice, + setBorrowRate, + getBorrowRate, + pretendBorrow +}; diff --git a/test/Utils/JS.js b/test/Utils/JS.js new file mode 100644 index 000000000..78b038d62 --- /dev/null +++ b/test/Utils/JS.js @@ -0,0 +1,24 @@ +"use strict"; + +function dfn(val, def) { + return isFinite(val) ? val : def; +} + +function last(elems) { + return Array.isArray(elems) ? elems[elems.length - 1] : elems; +} + +function lookup(obj, path = []) { + return Array.isArray(path) ? path.reduce((a, k) => a[k], obj) : obj[path]; +} + +function select(obj, keys = []) { + return keys.reduce((a, k) => (a[k] = obj[k], a), {}) +} + +module.exports = { + dfn, + last, + lookup, + select +}; diff --git a/test/Utils/MochaTruffle.js b/test/Utils/MochaTruffle.js new file mode 100644 index 000000000..75d5f49f1 --- /dev/null +++ b/test/Utils/MochaTruffle.js @@ -0,0 +1,266 @@ +"use strict"; + +const BigNum = require('bignumber.js'); +const ethers = require('ethers'); + +const {ComptrollerErr, TokenErr, IRErr, MathErr} = require('../Errors'); +const { + last, + lookup, + select +} = require('./JS'); + +async function asIfTesting(env = global) { + // Use this from a nodejs-repl, or something, to get a setup like tests have + const Config = require('truffle-config'); + const Resolver = require('truffle-resolver'); + const TestSource = require('truffle-core/lib/testing/testsource'); + const TestResolver = require('truffle-core/lib/testing/testresolver'); + const config = Config.detect(); + config.network = 'development'; + config.resolver = new Resolver(config); + + const test_source = new TestSource(config); + const test_resolver = new TestResolver(config.resolver, test_source, config.contracts_build_directory); + + env.web3 = new (require('web3'))(config.provider); + env.accounts = await env.web3.eth.getAccounts(); + env.artifacts = test_resolver; + env.artifacts.reset = () => Object.keys(env.artifacts.require_cache).map(k => delete env.artifacts.require_cache[k]); + env.config = config; + return env; +} + +const assert = Object.assign(global.assert || require('assert'), { + addressZero: (actual) => { + assert.equal(actual, address(0), `expected ${address(0)}, but got ${actual}`); + }, + + each: (assertion, actuals, expecteds, reason) => { + actuals.forEach((actual, i) => assert[assertion](actual, expecteds[i], reason)); + }, + + hasTrollError: (actual, expectedErrorName) => assert.hasError(actual, expectedErrorName, ComptrollerErr), + hasTokenError: (actual, expectedErrorName) => assert.hasError(actual, expectedErrorName, TokenErr), + hasError: (actual, expectedErrorName, reporter=TokenErr) => { + let actualErrorCode = actual instanceof Object ? actual[0] : actual; + assert.equal(actualErrorCode, reporter.Error[expectedErrorName], `expected Error.${expectedErrorName}, instead got Error.${reporter.ErrorInv[actualErrorCode]}`); + }, + + hasLog: (result, event, params) => { + const events = result.events; + const log = lookup(events, event); + if (!log) + assert.fail(0, 1, `expected log with event '${event}', found logs with events: ${Object.keys(events)}`); + assert.partEqual(log.returnValues, params); + }, + + hasNoLog: (result, event) => { + assert.equal(lookup(result.events, event), null); + }, + + hasTrollFailure: (result, err, info, detail=undefined) => assert.hasFailure(result, err, info, detail, ComptrollerErr), + hasTokenFailure: (result, err, info, detail=undefined) => assert.hasFailure(result, err, info, detail, TokenErr), + hasFailure: (result, expectedError, expectedInfo, expectedDetail=undefined, reporter=TokenErr) => { + const events = result.events; + const log = last(events['Failure']); + if (!log) + assert.fail(0, 1, `expected failure, but none found, founds logs with events: ${Object.keys(events)}`); + const ret = log.returnValues; + assert.equal(ret.error, reporter.Error[expectedError], `expected Error.${expectedError} (FailureInfo.${expectedInfo}), instead got Error.${reporter.ErrorInv[ret.error]} (FailureInfo.${reporter.FailureInfoInv[ret.info]}) [${ret.detail}]`); + assert.equal(ret.info, reporter.FailureInfo[expectedInfo], `expected (Error.${expectedError}) FailureInfo.${expectedInfo}, instead got (Error.${reporter.ErrorInv[ret.error]}) FailureInfo.${reporter.FailureInfoInv[ret.info]} [${ret.detail}]`); + if (expectedDetail !== undefined) + assert.equal(ret.detail, expectedDetail); + }, + + hasTokenMathFail: (result, info, detail) => { + assert.hasTokenFailure(result, 'MATH_ERROR', info, detail && (MathErr.Error[detail] || -1)); + }, + + hasTrollReject: (result, info, detail) => { + assert.hasTokenFailure(result, 'COMPTROLLER_REJECTION', info, detail && ComptrollerErr.Error[detail]); + }, + + hasIRErrorTuple: (result, tuple) => assert.hasErrorTuple(result, tuple, IRErr), + hasMathErrorTuple: (result, tuple) => assert.hasErrorTuple(result, tuple, MathErr), + hasTrollErrorTuple: (result, tuple) => assert.hasErrorTuple(result, tuple, ComptrollerErr), + hasTokenErrorTuple: (result, tuple) => assert.hasErrorTuple(result, tuple, TokenErr), + hasErrorTuple: (result, tuple, reporter=TokenErr) => { + assert.hasError(result[0], tuple[0], reporter); + assert.like(result[1], tuple[1]); + if (tuple[2] !== undefined) + assert.like(result[2], tuple[2]); + }, + + like: (actual, expected, reason) => { + if (typeof(expected) == 'function') + return expected(actual, reason); + assert.equal(actual, expected, reason); + }, + + numEqual: (actual, expected, reason) => { + assert.equal(actual.toString(), expected.toString(), reason); + }, + + numNotEqual: (actual, expected, reason) => { + assert.notEqual(actual.toString(), expected.toString(), reason); + }, + + partEqual: (actual, partial, reason) => { + assert.deepEqual(select(actual, Object.keys(partial)), partial, reason); + }, + + revert: async (trx, reason='revert') => { + // coverage tests don't currently support checking full message given with a revert + let result; + try { + result = await trx; + } catch (err) { + assert.equal(err.message, `Returned error: VM Exception while processing transaction: ${reason}`); + return; + } + assert.fail(0, 1, `expected revert, instead got result: ${JSON.stringify(result)}`); + }, + + revertWithError: async (trx, expectedErrorName, reason='revert', reporter=TokenErr) => { + assert.revert(trx, `${reason} (${reporter.Error[expectedErrorName].padStart(2, '0')})`) + }, + + succeeds: async (contract, method, args = [], opts = [], reporter=TokenErr) => { + const {reply, receipt} = await both(contract, method, args, opts); + assert.success(receipt); + assert.hasError(reply, 'NO_ERROR', reporter); + }, + + tokenSuccess: (result) => assert.success(result, TokenErr), + trollSuccess: (result) => assert.success(result, ComptrollerErr), + success: (result, reporter=TokenErr) => { + const events = result.events; + if (events['Failure']) { + const failure = last(events['Failure']); + const error = reporter.ErrorInv[failure.returnValues[0]]; + const failureInfo = reporter.FailureInfoInv[failure.returnValues[1]]; + let detail = failure.returnValues[2]; + if (detail && error == 'MATH_ERROR') + detail = MathErr.ErrorInv[detail]; + assert.fail(0, 1, `expected success, instead got failure: ${JSON.stringify(failure)} (Error: ${error}, FailureInfo: ${failureInfo}, Detail: ${detail})`) + } + return result; + } +}); + +function address(n) { + return `0x${(n).toString(16).padStart(40, '0')}`; +} + +async function etherBalance(addr) { + return ethers.utils.bigNumberify(new BigNum(await web3.eth.getBalance(addr)).toFixed()); +} + +async function etherGasCost(receipt) { + const tx = await web3.eth.getTransaction(receipt.transactionHash); + const gasUsed = new BigNum(receipt.gasUsed); + const gasPrice = new BigNum(tx.gasPrice); + return ethers.utils.bigNumberify(gasUsed.times(gasPrice).toFixed()); +} + +function etherMantissa(num) { + if (num < 0) + return ethers.utils.bigNumberify(new BigNum(2).pow(256).plus(num).toFixed()); + return ethers.utils.bigNumberify(new BigNum(num).times(1e18).toFixed()); +} + +function etherUnsigned(num) { + return ethers.utils.bigNumberify(new BigNum(num).toFixed()); +} + +function getContractDefaults() { + if (process.env.NETWORK === 'coverage') + return {gas: 0xfffffffffff, gasPrice: 1}; + return {gas: 20000000, gasPrice: 20000}; +} + +function getContract(name, opts = getContractDefaults()) { + const code = artifacts.require(name); + const contract = new web3.eth.Contract(code._json.abi, null, {data: code._json.bytecode, ...opts}); + contract.at = (addr) => { + return new web3.eth.Contract(code._json.abi, addr, {data: code._json.bytecode, ...opts}); + } + return contract; +} + +function getTestContract(name, opts) { + return getContract(name, opts); +} + +async function guessRoot() { + if (!global.accounts) + global.accounts = await web3.eth.getAccounts(); + return accounts[0]; +} + +async function minerStart() { + return rpc({method: 'miner_start'}); +} + +async function minerStop() { + return rpc({method: 'miner_stop'}); +} + +async function rpc(request) { + return new Promise((okay, fail) => web3.currentProvider.send(request, (err, res) => err ? fail(err) : okay(res))); +} + +async function both(contract, method, args = [], opts = {}) { + const reply = await call(contract, method, args, opts); + const receipt = await send(contract, method, args, opts); + return {reply, receipt}; +} + +async function call(contract, method, args = [], opts = {}) { + const { + from = await guessRoot(), + ...etc + } = opts || {}; + return contract.methods[method](...args).call({from, ...etc}); +} + +async function callUnsigned(contract, method, args = [], opts = {}) { + return etherUnsigned(await call(contract, method, args, opts)); +} + +async function send(contract, method, args = [], opts = {}) { + const { + from = await guessRoot(), + ...etc + } = opts || {}; + return contract.methods[method](...args).send({from, ...etc}); +} + +async function sendFallback(contract, opts = {}) { + const receipt = await web3.eth.sendTransaction({to: contract._address, ...opts}); + return Object.assign(receipt, {events: receipt.logs}); +} + +module.exports = { + asIfTesting, + assert, + address, + etherBalance, + etherGasCost, + etherMantissa, + etherUnsigned, + getContract, + getTestContract, + guessRoot, + + minerStart, + minerStop, + rpc, + + both, + call, + callUnsigned, + send, + sendFallback +}; diff --git a/test/contracts/BasicToken.sol b/test/contracts/BasicToken.sol new file mode 100644 index 000000000..f671d1164 --- /dev/null +++ b/test/contracts/BasicToken.sol @@ -0,0 +1,50 @@ +pragma solidity ^0.5.8; + + +import "./ERC20Basic.sol"; +import "./SafeMath.sol"; + + +/** + * @title Basic token + * @dev Basic version of StandardToken, with no allowances. + */ +contract BasicToken is ERC20Basic { + using SafeMath for uint256; + + mapping(address => uint256) balances; + + uint256 totalSupply_; + + /** + * @dev Total number of tokens in existence + */ + function totalSupply() public view returns (uint256) { + return totalSupply_; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_to != address(0)); + require(_value <= balances[msg.sender]); + + balances[msg.sender] = balances[msg.sender].sub(_value); + balances[_to] = balances[_to].add(_value); + emit Transfer(msg.sender, _to, _value); + return true; + } + + /** + * @dev Gets the balance of the specified address. + * @param _owner The address to query the the balance of. + * @return An uint256 representing the amount owned by the passed address. + */ + function balanceOf(address _owner) public view returns (uint256) { + return balances[_owner]; + } + +} \ No newline at end of file diff --git a/test/contracts/BasicTokenNS.sol b/test/contracts/BasicTokenNS.sol new file mode 100644 index 000000000..97bac6af0 --- /dev/null +++ b/test/contracts/BasicTokenNS.sol @@ -0,0 +1,50 @@ +pragma solidity ^0.5.8; + + +import "./ERC20BasicNS.sol"; +import "./SafeMath.sol"; + +/** + * @title Basic token (Non-Standard) + * @dev Basic version of NonStandardToken, with no allowances. + * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` + * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca + */ +contract BasicTokenNS is ERC20BasicNS { + using SafeMath for uint256; + + mapping(address => uint256) balances; + + uint256 totalSupply_; + + /** + * @dev Total number of tokens in existence + */ + function totalSupply() public view returns (uint256) { + return totalSupply_; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public { + require(_to != address(0)); + require(_value <= balances[msg.sender]); + + balances[msg.sender] = balances[msg.sender].sub(_value); + balances[_to] = balances[_to].add(_value); + emit Transfer(msg.sender, _to, _value); + } + + /** + * @dev Gets the balance of the specified address. + * @param _owner The address to query the the balance of. + * @return An uint256 representing the amount owned by the passed address. + */ + function balanceOf(address _owner) public view returns (uint256) { + return balances[_owner]; + } + +} \ No newline at end of file diff --git a/test/contracts/BoolComptroller.sol b/test/contracts/BoolComptroller.sol new file mode 100644 index 000000000..d788f9d87 --- /dev/null +++ b/test/contracts/BoolComptroller.sol @@ -0,0 +1,278 @@ +pragma solidity ^0.5.8; + +import "../ComptrollerInterface.sol"; + +contract BoolComptroller is ComptrollerInterface { + bool public isComptroller = true; + + bool allowMint = true; + bool allowRedeem = true; + bool allowBorrow = true; + bool allowRepayBorrow = true; + bool allowLiquidateBorrow = true; + bool allowSeize = true; + bool allowTransfer = true; + + bool verifyMint = true; + bool verifyRedeem = true; + bool verifyBorrow = true; + bool verifyRepayBorrow = true; + bool verifyLiquidateBorrow = true; + bool verifySeize = true; + bool verifyTransfer = true; + + bool failCalculateSeizeTokens; + uint calculatedSeizeTokens; + + uint noError = 0; + uint opaqueError = noError + 11; // an arbitrary, opaque error code + + /*** Assets You Are In ***/ + + function enterMarkets(address[] calldata _cTokens) external returns (uint[] memory) { + _cTokens; + uint[] memory ret; + return ret; + } + + function exitMarket(address _cToken) external returns (uint) { + _cToken; + return noError; + } + + /*** Policy Hooks ***/ + + function mintAllowed(address _cToken, address _minter, uint _mintAmount) public returns (uint) { + _cToken; + _minter; + _mintAmount; + return allowMint ? noError : opaqueError; + } + + function mintVerify(address _cToken, address _minter, uint _mintAmount, uint _mintTokens) external { + _cToken; + _minter; + _mintAmount; + _mintTokens; + require(verifyMint, "mintVerify rejected mint"); + } + + function redeemAllowed(address _cToken, address _redeemer, uint _redeemTokens) public returns (uint) { + _cToken; + _redeemer; + _redeemTokens; + return allowRedeem ? noError : opaqueError; + } + + function redeemVerify(address _cToken, address _redeemer, uint _redeemAmount, uint _redeemTokens) external { + _cToken; + _redeemer; + _redeemAmount; + _redeemTokens; + require(verifyRedeem, "redeemVerify rejected redeem"); + } + + function borrowAllowed(address _cToken, address _borrower, uint _borrowAmount) public returns (uint) { + _cToken; + _borrower; + _borrowAmount; + return allowBorrow ? noError : opaqueError; + } + + function borrowVerify(address _cToken, address _borrower, uint _borrowAmount) external { + _cToken; + _borrower; + _borrowAmount; + require(verifyBorrow, "borrowVerify rejected borrow"); + } + + function repayBorrowAllowed( + address _cToken, + address _payer, + address _borrower, + uint _repayAmount) public returns (uint) { + _cToken; + _payer; + _borrower; + _repayAmount; + return allowRepayBorrow ? noError : opaqueError; + } + + function repayBorrowVerify( + address _cToken, + address _payer, + address _borrower, + uint _repayAmount, + uint _borrowerIndex) external { + _cToken; + _payer; + _borrower; + _repayAmount; + _borrowerIndex; + require(verifyRepayBorrow, "repayBorrowVerify rejected repayBorrow"); + } + + function liquidateBorrowAllowed( + address _cTokenBorrowed, + address _cTokenCollateral, + address _liquidator, + address _borrower, + uint _repayAmount) public returns (uint) { + _cTokenBorrowed; + _cTokenCollateral; + _liquidator; + _borrower; + _repayAmount; + return allowLiquidateBorrow ? noError : opaqueError; + } + + function liquidateBorrowVerify( + address _cTokenBorrowed, + address _cTokenCollateral, + address _liquidator, + address _borrower, + uint _repayAmount, + uint _seizeTokens) external { + _cTokenBorrowed; + _cTokenCollateral; + _liquidator; + _borrower; + _repayAmount; + _seizeTokens; + require(verifyLiquidateBorrow, "liquidateBorrowVerify rejected liquidateBorrow"); + } + + function seizeAllowed( + address _cTokenCollateral, + address _cTokenBorrowed, + address _borrower, + address _liquidator, + uint _seizeTokens) public returns (uint) { + _cTokenCollateral; + _cTokenBorrowed; + _liquidator; + _borrower; + _seizeTokens; + return allowSeize ? noError : opaqueError; + } + + function seizeVerify( + address _cTokenCollateral, + address _cTokenBorrowed, + address _liquidator, + address _borrower, + uint _seizeTokens) external { + _cTokenCollateral; + _cTokenBorrowed; + _liquidator; + _borrower; + _seizeTokens; + require(verifySeize, "seizeVerify rejected seize"); + } + + function transferAllowed( + address _cToken, + address _src, + address _dst, + uint _transferTokens) public returns (uint) { + _cToken; + _src; + _dst; + _transferTokens; + return allowTransfer ? noError : opaqueError; + } + + function transferVerify( + address _cToken, + address _src, + address _dst, + uint _transferTokens) external { + _cToken; + _src; + _dst; + _transferTokens; + require(verifyTransfer, "transferVerify rejected transfer"); + } + + /*** Special Liquidation Calculation ***/ + + function liquidateCalculateSeizeTokens( + address _cTokenBorrowed, + address _cTokenCollateral, + uint _repayAmount) public view returns (uint, uint) { + _cTokenBorrowed; + _cTokenCollateral; + _repayAmount; + return failCalculateSeizeTokens ? (opaqueError, 0) : (noError, calculatedSeizeTokens); + } + + /**** Mock Settors ****/ + + /*** Policy Hooks ***/ + + function setMintAllowed(bool allowMint_) public { + allowMint = allowMint_; + } + + function setMintVerify(bool verifyMint_) public { + verifyMint = verifyMint_; + } + + function setRedeemAllowed(bool allowRedeem_) public { + allowRedeem = allowRedeem_; + } + + function setRedeemVerify(bool verifyRedeem_) public { + verifyRedeem = verifyRedeem_; + } + + function setBorrowAllowed(bool allowBorrow_) public { + allowBorrow = allowBorrow_; + } + + function setBorrowVerify(bool verifyBorrow_) public { + verifyBorrow = verifyBorrow_; + } + + function setRepayBorrowAllowed(bool allowRepayBorrow_) public { + allowRepayBorrow = allowRepayBorrow_; + } + + function setRepayBorrowVerify(bool verifyRepayBorrow_) public { + verifyRepayBorrow = verifyRepayBorrow_; + } + + function setLiquidateBorrowAllowed(bool allowLiquidateBorrow_) public { + allowLiquidateBorrow = allowLiquidateBorrow_; + } + + function setLiquidateBorrowVerify(bool verifyLiquidateBorrow_) public { + verifyLiquidateBorrow = verifyLiquidateBorrow_; + } + + function setSeizeAllowed(bool allowSeize_) public { + allowSeize = allowSeize_; + } + + function setSeizeVerify(bool verifySeize_) public { + verifySeize = verifySeize_; + } + + function setTransferAllowed(bool allowTransfer_) public { + allowTransfer = allowTransfer_; + } + + function setTransferVerify(bool verifyTransfer_) public { + verifyTransfer = verifyTransfer_; + } + + /*** Liquidity/Liquidation Calculations ***/ + + function setCalculatedSeizeTokens(uint seizeTokens_) public { + calculatedSeizeTokens = seizeTokens_; + } + + function setFailCalculateSeizeTokens(bool shouldFail) public { + failCalculateSeizeTokens = shouldFail; + } +} diff --git a/test/contracts/CErc20Harness.sol b/test/contracts/CErc20Harness.sol new file mode 100644 index 000000000..2657096ee --- /dev/null +++ b/test/contracts/CErc20Harness.sol @@ -0,0 +1,187 @@ +pragma solidity ^0.5.8; + +import "../CErc20.sol"; + +contract CErc20Harness is CErc20 { + + uint blockNumber = 100000; + uint harnessExchangeRate; + bool harnessExchangeRateStored; + + /* + To support testing, we allow the contract to always fail `transfer`. + */ + mapping (address => bool) public failTransferToAddresses; + + constructor(address underlying_, + ComptrollerInterface comptroller_, + InterestRateModel interestRateModel_, + uint initialExchangeRateMantissa, + string memory name_, + string memory symbol_, + uint decimals_) + CErc20( + underlying_, + comptroller_, + interestRateModel_, + initialExchangeRateMantissa, + name_, + symbol_, + decimals_) public {} + + /** + * Fresh + * + */ + function getBlockNumber() internal view returns (uint) { + return blockNumber; + } + + function harnessSetBlockNumber(uint newBlockNumber) public { + blockNumber = newBlockNumber; + } + + function harnessFastForward(uint blocks) public { + blockNumber += blocks; + } + + /** + * Account Balances + * + */ + function harnessSetBalance(address account, uint amount) external { + accountTokens[account] = amount; + } + + /** + * Accrual Block Number + */ + function harnessSetAccrualBlockNumber(uint _accrualblockNumber) public { + accrualBlockNumber = _accrualblockNumber; + } + + /** + * Exchange Rate + * + */ + function harnessSetTotalSupply(uint totalSupply_) public { + totalSupply = totalSupply_; + } + + function harnessSetTotalBorrows(uint totalBorrows_) public { + totalBorrows = totalBorrows_; + } + + function harnessSetTotalReserves(uint totalReserves_) public { + totalReserves = totalReserves_; + } + + function harnessExchangeRateDetails(uint totalSupply_, uint totalBorrows_, uint totalReserves_) public { + totalSupply = totalSupply_; + totalBorrows = totalBorrows_; + totalReserves = totalReserves_; + } + + function harnessSetExchangeRate(uint exchangeRate) public { + harnessExchangeRate = exchangeRate; + harnessExchangeRateStored = true; + } + + function exchangeRateStoredInternal() internal view returns (MathError, uint) { + if (harnessExchangeRateStored) { + return (MathError.NO_ERROR, harnessExchangeRate); + } + + return super.exchangeRateStoredInternal(); + } + + /** + * Transfer Harness methods + * + */ + + /** + * @dev Specify `address, true` to cause transfers to address to fail. + * Once an address has been marked for failure it can be cleared by + * with `address, false` + */ + function harnessSetFailTransferToAddress(address _to, bool _fail) public { + failTransferToAddresses[_to] = _fail; + } + + function doTransferOut(address payable to, uint amount) internal returns (Error) { + if (failTransferToAddresses[to]) { + return Error.TOKEN_TRANSFER_OUT_FAILED; + } + return super.doTransferOut(to, amount); + } + + /** + * Spearmint? Nah, fresh mint. + * + */ + function harnessMintFresh(address account, uint mintAmount) public returns (uint) { + return super.mintFresh(account, mintAmount); + } + + /** + * Redemption + * + */ + function harnessRedeemFresh(address payable account, uint cTokenAmount, uint underlyingAmount) public returns (uint) { + return super.redeemFresh(account, cTokenAmount, underlyingAmount); + } + + /** + * Borrowing + * + */ + function harnessAccountBorrows(address account) public view returns (uint principal, uint interestIndex) { + BorrowSnapshot memory snapshot = accountBorrows[account]; + return (snapshot.principal, snapshot.interestIndex); + } + + function harnessSetAccountBorrows(address account, uint principal, uint interestIndex) public { + accountBorrows[account] = BorrowSnapshot({principal: principal, interestIndex: interestIndex}); + } + + function harnessSetBorrowIndex(uint borrowIndex_) public { + borrowIndex = borrowIndex_; + } + + function harnessBorrowFresh(address payable account, uint borrowAmount) public returns (uint) { + return borrowFresh(account, borrowAmount); + } + + function harnessRepayBorrowFresh(address payer, address account, uint borrowAmount) public returns (uint) { + return repayBorrowFresh(payer, account, borrowAmount); + } + + function harnessLiquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, CToken cTokenCollateral) public returns (uint) { + return liquidateBorrowFresh(liquidator, borrower, repayAmount, cTokenCollateral); + } + + /** + * Admin + * + */ + function harnessReduceReservesFresh(uint amount) public returns (uint) { + return _reduceReservesFresh(amount); + } + + function harnessSetReserveFactorFresh(uint newReserveFactorMantissa) public returns (uint) { + return _setReserveFactorFresh(newReserveFactorMantissa); + } + + function harnessSetInterestRateModelFresh(InterestRateModel newInterestRateModel) public returns (uint) { + return _setInterestRateModelFresh(newInterestRateModel); + } + + /** + * @dev set the interest rate model directly, with no interest accrual and no checks + * Intended for linking in FailableInterestRateModel to create failures in accrueInterest + */ + function harnessSetInterestRateModel(address newInterestRateModelAddress) public { + interestRateModel = InterestRateModel(newInterestRateModelAddress); + } +} diff --git a/test/contracts/CErc20Scenario.sol b/test/contracts/CErc20Scenario.sol new file mode 100644 index 000000000..408bf04b3 --- /dev/null +++ b/test/contracts/CErc20Scenario.sol @@ -0,0 +1,40 @@ +pragma solidity ^0.5.8; + +import "../CErc20.sol"; +import "./ComptrollerScenario.sol"; + +contract CErc20Scenario is CErc20 { + constructor(address underlying_, + ComptrollerInterface comptroller_, + InterestRateModel interestRateModel_, + uint initialExchangeRateMantissa, + string memory name_, + string memory symbol_, + uint decimals_) + CErc20( + underlying_, + comptroller_, + interestRateModel_, + initialExchangeRateMantissa, + name_, + symbol_, + decimals_) public {} + + function setTotalBorrows(uint totalBorrows_) public { + totalBorrows = totalBorrows_; + } + + function setTotalReserves(uint totalReserves_) public { + totalReserves = totalReserves_; + } + + /** + * @dev Function to simply retrieve block number + * This exists mainly for inheriting test contracts to stub this result. + */ + function getBlockNumber() internal view returns (uint) { + ComptrollerScenario comptrollerScenario = ComptrollerScenario(address(comptroller)); + + return comptrollerScenario.blockNumber(); + } +} diff --git a/test/contracts/CEtherHarness.sol b/test/contracts/CEtherHarness.sol new file mode 100644 index 000000000..6b25cceca --- /dev/null +++ b/test/contracts/CEtherHarness.sol @@ -0,0 +1,207 @@ +pragma solidity ^0.5.8; + +import "../CEther.sol"; + +contract CEtherHarness is CEther { + + uint harnessExchangeRate; + uint public blockNumber = 100000; + + /* + To support testing, we allow the contract to always fail `transfer`. + */ + mapping (address => bool) public failTransferToAddresses; + + constructor(ComptrollerInterface comptroller_, + InterestRateModel interestRateModel_, + uint initialExchangeRateMantissa, + string memory name_, + string memory symbol_, + uint decimals_) + CEther( + comptroller_, + interestRateModel_, + initialExchangeRateMantissa, + name_, + symbol_, + decimals_) public {} + + /** + * Fresh + * + */ + function getBlockNumber() internal view returns (uint) { + return blockNumber; + } + + function harnessSetBlockNumber(uint newBlockNumber) public { + blockNumber = newBlockNumber; + } + + function harnessFastForward(uint blocks) public { + blockNumber += blocks; + } + + /** + * Account Balances + * + */ + function harnessSetBalance(address account, uint amount) external { + accountTokens[account] = amount; + } + + /** + * Accrual Block Number + */ + function harnessSetAccrualBlockNumber(uint _accrualblockNumber) public { + accrualBlockNumber = _accrualblockNumber; + } + + /** + * Exchange Rate + * + */ + function harnessSetTotalSupply(uint totalSupply_) public { + totalSupply = totalSupply_; + } + + function harnessSetTotalBorrows(uint totalBorrows_) public { + totalBorrows = totalBorrows_; + } + + function harnessSetTotalReserves(uint totalReserves_) public { + totalReserves = totalReserves_; + } + + function harnessExchangeRateDetails(uint _totalSupply, uint _totalBorrows, uint _totalReserves) public { + totalSupply = _totalSupply; + totalBorrows = _totalBorrows; + totalReserves = _totalReserves; + } + + function harnessSetExchangeRate(uint exchangeRate) public { + harnessExchangeRate = exchangeRate; + } + + function exchangeRateStoredInternal() internal view returns (MathError, uint) { + if (harnessExchangeRate != 0) { + return (MathError.NO_ERROR, harnessExchangeRate); + } + + return super.exchangeRateStoredInternal(); + } + + /** + * Transfer Harness methods + * + */ + + /** + * @dev Specify `address, true` to cause transfers to address to fail. + * Once an address has been marked for failure it can be cleared by + * with `address, false` + */ + function harnessSetFailTransferToAddress(address _to, bool _fail) public { + failTransferToAddresses[_to] = _fail; + } + + function doTransferOut(address payable to, uint amount) internal returns (Error) { + if (failTransferToAddresses[to]) { + return Error.TOKEN_TRANSFER_OUT_FAILED; + } + return super.doTransferOut(to, amount); + } + + /** + * Spearmint? Nah, fresh mint. + * + */ + function harnessMintFresh(address account, uint mintAmount) public returns (uint) { + return super.mintFresh(account, mintAmount); + } + + /** + * Redemption + * + */ + function harnessRedeemFresh(address payable account, uint cTokenAmount, uint underlyingAmount) public returns (uint) { + return super.redeemFresh(account, cTokenAmount, underlyingAmount); + } + + /** + * Borrowing + * + */ + function harnessAccountBorrows(address account) public view returns (uint principal, uint interestIndex) { + BorrowSnapshot memory snapshot = accountBorrows[account]; + return (snapshot.principal, snapshot.interestIndex); + } + + function harnessSetAccountBorrows(address account, uint principal, uint interestIndex) public { + accountBorrows[account] = BorrowSnapshot({principal: principal, interestIndex: interestIndex}); + } + + function harnessSetBorrowIndex(uint borrowIndex_) public { + borrowIndex = borrowIndex_; + } + + function harnessBorrowFresh(address payable account, uint borrowAmount) public returns (uint) { + return borrowFresh(account, borrowAmount); + } + + function harnessRepayBorrowFresh(address payer, address account, uint borrowAmount) public payable returns (uint) { + return repayBorrowFresh(payer, account, borrowAmount); + } + + function harnessLiquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, CToken cTokenCollateral) public returns (uint) { + return liquidateBorrowFresh(liquidator, borrower, repayAmount, cTokenCollateral); + } + /** + * Admin + * + */ + function harnessReduceReservesFresh(uint amount) public returns (uint) { + return _reduceReservesFresh(amount); + } + + function harnessSetReserves(uint amount) public { + totalReserves = amount; + } + + function harnessSetReserveFactorFresh(uint newReserveFactorMantissa) public returns (uint) { + return _setReserveFactorFresh(newReserveFactorMantissa); + } + + function harnessSetInterestRateModelFresh(InterestRateModel newInterestRateModel) public returns (uint) { + return _setInterestRateModelFresh(newInterestRateModel); + } + + /** + * @dev set the interest rate model directly, with no interest accrual and no checks + * Intended for linking in FailableInterestRateModel to create failures in accrueInterest + */ + function harnessSetInterestRateModel(address newInterestRateModelAddress) public { + interestRateModel = InterestRateModel(newInterestRateModelAddress); + } + + /** safe token harnes **/ + function harnessGetCashPrior() public payable returns (uint) { + return getCashPrior(); + } + + function harnessDoTransferIn(address from, uint amount) public payable returns (uint) { + return uint(doTransferIn(from, amount)); + } + + function harnessDoTransferOut(address payable to, uint amount) public payable returns (uint) { + return uint(doTransferOut(to, amount)); + } + + function harnessCheckTransferIn(address from, uint amount) external payable returns (uint) { + return uint(checkTransferIn(from, amount)); + } + + function harnessRequireNoError(uint error, string calldata message) external pure { + requireNoError(error, message); + } +} diff --git a/test/contracts/CEtherScenario.sol b/test/contracts/CEtherScenario.sol new file mode 100644 index 000000000..3e10b6e7a --- /dev/null +++ b/test/contracts/CEtherScenario.sol @@ -0,0 +1,44 @@ +pragma solidity ^0.5.8; + +import "../CEther.sol"; +import "./ComptrollerScenario.sol"; + +contract CEtherScenario is CEther { + uint reserveFactor; + + constructor(string memory name_, + string memory symbol_, + uint8 decimals_, + ComptrollerInterface comptroller_, + InterestRateModel interestRateModel_, + uint initialExchangeRateMantissa) + CEther(comptroller_, + interestRateModel_, + initialExchangeRateMantissa, + name_, + symbol_, + decimals_) public { + } + + function setTotalBorrows(uint totalBorrows_) public { + totalBorrows = totalBorrows_; + } + + function setTotalReserves(uint totalReserves_) public { + totalReserves = totalReserves_; + } + + function donate() public payable { + // no-op + } + + /** + * @dev Function to simply retrieve block number + * This exists mainly for inheriting test contracts to stub this result. + */ + function getBlockNumber() internal view returns (uint) { + ComptrollerScenario comptrollerScenario = ComptrollerScenario(address(comptroller)); + + return comptrollerScenario.blockNumber(); + } +} diff --git a/test/contracts/CEvil.sol b/test/contracts/CEvil.sol new file mode 100644 index 000000000..0490a4977 --- /dev/null +++ b/test/contracts/CEvil.sol @@ -0,0 +1,25 @@ +pragma solidity ^0.5.8; + +import "./CErc20Scenario.sol"; + +contract CEvil is CErc20Scenario { + constructor(address underlying_, + ComptrollerInterface comptroller_, + InterestRateModel interestRateModel_, + uint initialExchangeRateMantissa, + string memory name_, + string memory symbol_, + uint decimals_) + CErc20Scenario( + underlying_, + comptroller_, + interestRateModel_, + initialExchangeRateMantissa, + name_, + symbol_, + decimals_) public {} + + function evilSeize(CToken treasure, address liquidator, address borrower, uint seizeTokens) public returns (uint) { + return treasure.seize(liquidator, borrower, seizeTokens); + } +} diff --git a/test/contracts/ComptrollerBorked.sol b/test/contracts/ComptrollerBorked.sol new file mode 100644 index 000000000..188960293 --- /dev/null +++ b/test/contracts/ComptrollerBorked.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.5.8; + +import "../Comptroller.sol"; +import "../PriceOracle.sol"; + +contract ComptrollerBorked { + + function _become(Unitroller unitroller, PriceOracle _oracle, uint _closeFactorMantissa, uint _maxAssets, bool _reinitializing) public { + _oracle; + _closeFactorMantissa; + _maxAssets; + _reinitializing; + + require(msg.sender == unitroller.admin(), "only unitroller admin can change brains"); + unitroller._acceptImplementation(); + } + +} diff --git a/test/contracts/ComptrollerHarness.sol b/test/contracts/ComptrollerHarness.sol new file mode 100644 index 000000000..182a673a5 --- /dev/null +++ b/test/contracts/ComptrollerHarness.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.5.8; + +import "../Comptroller.sol"; +import "../PriceOracle.sol"; + +contract ComptrollerHarness is Comptroller { + constructor() Comptroller() public {} + + function getHypotheticalAccountLiquidity( + address account, + address cTokenModify, + uint redeemTokens, + uint borrowAmount) public view returns (uint, uint, uint) { + (Error err, uint liquidity, uint shortfall) = + super.getHypotheticalAccountLiquidityInternal(account, CToken(cTokenModify), redeemTokens, borrowAmount); + return (uint(err), liquidity, shortfall); + } +} diff --git a/test/contracts/ComptrollerScenario.sol b/test/contracts/ComptrollerScenario.sol new file mode 100644 index 000000000..4e3198e49 --- /dev/null +++ b/test/contracts/ComptrollerScenario.sol @@ -0,0 +1,48 @@ +pragma solidity ^0.5.8; + +import "../Comptroller.sol"; +import "../PriceOracle.sol"; + +contract ComptrollerScenario is Comptroller { + uint public blockNumber; + + constructor() Comptroller() public {} + + function membershipLength(CToken cToken) public view returns (uint) { + return accountAssets[address(cToken)].length; + } + + function fastForward(uint blocks) public returns (uint) { + blockNumber += blocks; + + return blockNumber; + } + + function setBlockNumber(uint number) public { + blockNumber = number; + } + + function _become(Unitroller unitroller, PriceOracle _oracle, uint _closeFactorMantissa, uint _maxAssets, bool reinitializing) public { + super._become(unitroller, _oracle, _closeFactorMantissa, _maxAssets, reinitializing); + + if (!reinitializing) { + ComptrollerScenario freshBrainedComptroller = ComptrollerScenario(address(unitroller)); + + freshBrainedComptroller.setBlockNumber(100000); + } + } + + function getHypotheticalAccountLiquidity( + address account, + address cTokenModify, + uint redeemTokens, + uint borrowAmount) public view returns (uint, uint, uint) { + (Error err, uint liquidity, uint shortfall) = + super.getHypotheticalAccountLiquidityInternal(account, CToken(cTokenModify), redeemTokens, borrowAmount); + return (uint(err), liquidity, shortfall); + } + + function unlist(CToken cToken) public { + markets[address(cToken)].isListed = false; + } +} diff --git a/test/contracts/DSValueHarness.sol b/test/contracts/DSValueHarness.sol new file mode 100644 index 000000000..c9ab2f933 --- /dev/null +++ b/test/contracts/DSValueHarness.sol @@ -0,0 +1,32 @@ +// Abstract contract for the full DSValue standard +// -- +pragma solidity ^0.5.8; + +contract DSValueHarness { + bool public has; + bytes32 public val; + + constructor(bytes32 initVal) public { + if (initVal != 0) { + has = true; + val = initVal; + } + } + + function peek() public view returns (bytes32, bool) { + return (val, has); + } + + function read() public view returns (bytes32) { + return val; + } + + function set(bytes32 _val) public { + val = _val; + has = true; + } + + function unset() public { + has = false; + } +} \ No newline at end of file diff --git a/test/contracts/EIP20Harness.sol b/test/contracts/EIP20Harness.sol new file mode 100644 index 000000000..d67ce8328 --- /dev/null +++ b/test/contracts/EIP20Harness.sol @@ -0,0 +1,123 @@ +/* +Implements EIP20 token standard: https://github.com/ethereum/EIPs/issues/20 +.*/ + +pragma solidity ^0.5.8; + +import "../EIP20Interface.sol"; + +contract EIP20Harness is EIP20Interface { + + uint256 constant private MAX_UINT256 = 2**256 - 1; + uint256 public totalSupply; + mapping (address => uint256) public balances; + mapping (address => mapping (address => uint256)) public allowed; + + /* + To support testing, we can specify addresses for which transferFrom should fail and return false. + See `harnessSetFailTransferFromAddress` + */ + mapping (address => bool) public failTransferFromAddresses; + + /* + To support testing, we allow the contract to always fail `transfer`. + */ + mapping (address => bool) public failTransferToAddresses; + + + /* + NOTE: + The following variables are OPTIONAL vanities. One does not have to include them. + They allow one to customise the token contract & in no way influences the core functionality. + Some wallets/interfaces might not even bother to look at this information. + */ + string public name; //fancy name: eg Simon Bucks + uint8 public decimals; //How many decimals to show. + string public symbol; //An identifier: eg SBX + + constructor( + uint256 _initialAmount, + string memory _tokenName, + uint8 _decimalUnits, + string memory _tokenSymbol + ) public { + balances[msg.sender] = _initialAmount; // Give the creator all initial tokens + totalSupply = _initialAmount; // Update total supply + name = _tokenName; // Set the name for display purposes + decimals = _decimalUnits; // Amount of decimals for display purposes + symbol = _tokenSymbol; // Set the symbol for display purposes + } + + + /** + * @dev Specify `address, true` to cause transfers from address to fail. + * Once an address has been marked for failure it can be cleared by + * with `address, false` + */ + function harnessSetFailTransferFromAddress(address _from, bool _fail) public { + failTransferFromAddresses[_from] = _fail; + } + + /** + * @dev Specify `address, true` to cause transfers to address to fail. + * Once an address has been marked for failure it can be cleared by + * with `address, false` + */ + function harnessSetFailTransferToAddress(address _to, bool _fail) public { + failTransferToAddresses[_to] = _fail; + } + + function harnessSetBalance(address _account, uint _amount) public { + balances[_account] = _amount; + } + + function transfer(address _to, uint256 _value) public returns (bool success) { + require(balances[msg.sender] >= _value); + + // Added for testing purposes + if (failTransferToAddresses[_to]) { + return false; + } + + balances[msg.sender] -= _value; + balances[_to] += _value; + emit Transfer(msg.sender, _to, _value); + return true; + } + + function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { + // Added for testing purposes + if (_from == address(0)) { + return false; + } + + // Added for testing purposes + if (failTransferFromAddresses[_from]) { + return false; + } + + uint256 allowance = allowed[_from][msg.sender]; + require(balances[_from] >= _value && allowance >= _value); + balances[_to] += _value; + balances[_from] -= _value; + if (allowance < MAX_UINT256) { + allowed[_from][msg.sender] -= _value; + } + emit Transfer(_from, _to, _value); + return true; + } + + function balanceOf(address _owner) public view returns (uint256 balance) { + return balances[_owner]; + } + + function approve(address _spender, uint256 _value) public returns (bool success) { + allowed[msg.sender][_spender] = _value; + emit Approval(msg.sender, _spender, _value); + return true; + } + + function allowance(address _owner, address _spender) public view returns (uint256 remaining) { + return allowed[_owner][_spender]; + } +} diff --git a/test/contracts/EIP20NonCompliantHarness.sol b/test/contracts/EIP20NonCompliantHarness.sol new file mode 100644 index 000000000..3034e15fc --- /dev/null +++ b/test/contracts/EIP20NonCompliantHarness.sol @@ -0,0 +1,27 @@ +/* +Implements `transfer` and `transferForm` with 64-bit return values, just to be +especially non-compliant and stress safe token. +.*/ + +pragma solidity ^0.5.8; + +contract EIP20NonCompliantHarness { + bool garbage; + + function transfer(address _to, uint256 _value) public returns (uint, uint) { + _to; + _value; // supress unused variable warning + garbage = false; + + return (1, 2); + } + + function transferFrom(address _from, address _to, uint256 _value) public returns (uint, uint) { + _from; + _to; + _value; // supress unused variable warning + garbage = false; + + return (1, 2); + } +} diff --git a/test/contracts/EIP20NonStandardReturnHarness.sol b/test/contracts/EIP20NonStandardReturnHarness.sol new file mode 100644 index 000000000..2d7e46342 --- /dev/null +++ b/test/contracts/EIP20NonStandardReturnHarness.sol @@ -0,0 +1,123 @@ +/* +Implements EIP20 token standard: https://github.com/ethereum/EIPs/issues/20 +.*/ + +pragma solidity ^0.5.8; + +import "../EIP20NonStandardInterface.sol"; + +// Note: the harness here does not throw for expected errors, which allows this +// harness to be used for Solidity tests. For JavaScript tests, use: EIP20NonStandardThrowHarness. +contract EIP20NonStandardReturnHarness is EIP20NonStandardInterface { + + uint256 constant private MAX_UINT256 = 2**256 - 1; + uint256 public totalSupply; + mapping (address => uint256) public balances; + mapping (address => mapping (address => uint256)) public allowed; + + /* + To support testing, we can specify addresses for which transferFrom should fail and return false. + See `harnessSetFailTransferFromAddress` + */ + mapping (address => bool) public failTransferFromAddresses; + + /* + To support testing, we allow the contract to always fail `transfer`. + */ + mapping (address => bool) public failTransferToAddresses; + + + /* + NOTE: + The following variables are OPTIONAL vanities. One does not have to include them. + They allow one to customise the token contract & in no way influences the core functionality. + Some wallets/interfaces might not even bother to look at this information. + */ + string public name; //fancy name: eg Simon Bucks + uint8 public decimals; //How many decimals to show. + string public symbol; //An identifier: eg SBX + + constructor( + uint256 _initialAmount, + string memory _tokenName, + uint8 _decimalUnits, + string memory _tokenSymbol + ) public { + balances[msg.sender] = _initialAmount; // Give the creator all initial tokens + totalSupply = _initialAmount; // Update total supply + name = _tokenName; // Set the name for display purposes + decimals = _decimalUnits; // Amount of decimals for display purposes + symbol = _tokenSymbol; // Set the symbol for display purposes + } + + + /** + * @dev Specify `address, true` to cause transfers from address to fail. + * Once an address has been marked for failure it can be cleared by + * with `address, false` + */ + function harnessSetFailTransferFromAddress(address _from, bool _fail) public { + failTransferFromAddresses[_from] = _fail; + } + + /** + * @dev Specify `address, true` to cause transfers to address to fail. + * Once an address has been marked for failure it can be cleared by + * with `address, false` + */ + function harnessSetFailTransferToAddress(address _to, bool _fail) public { + failTransferToAddresses[_to] = _fail; + } + + function harnessSetBalance(address _account, uint _amount) public { + balances[_account] = _amount; + } + + function transfer(address _to, uint256 _value) public { + require(balances[msg.sender] >= _value); + + // Added for testing purposes + if (failTransferToAddresses[_to]) { + return; + } + + balances[msg.sender] -= _value; + balances[_to] += _value; + emit Transfer(msg.sender, _to, _value); + } + + function transferFrom(address _from, address _to, uint256 _value) public { + // Added for testing purposes + if (_from == address(0)) { + return; + } + + // Added for testing purposes + if (failTransferFromAddresses[_from]) { + return; + } + + uint256 allowance = allowed[_from][msg.sender]; + require(balances[_from] >= _value && allowance >= _value); + balances[_to] += _value; + balances[_from] -= _value; + if (allowance < MAX_UINT256) { + allowed[_from][msg.sender] -= _value; + } + emit Transfer(_from, _to, _value); + } + + function balanceOf(address _owner) public view returns (uint256 balance) { + return balances[_owner]; + } + + function approve(address _spender, uint256 _value) public returns (bool success) { + allowed[msg.sender][_spender] = _value; + emit Approval(msg.sender, _spender, _value); + return true; + } + + function allowance(address _owner, address _spender) public view returns (uint256 remaining) { + return allowed[_owner][_spender]; + } +} diff --git a/test/contracts/EIP20NonStandardThrowHarness.sol b/test/contracts/EIP20NonStandardThrowHarness.sol new file mode 100644 index 000000000..e47580d3d --- /dev/null +++ b/test/contracts/EIP20NonStandardThrowHarness.sol @@ -0,0 +1,123 @@ +/* +Implements EIP20 token standard: https://github.com/ethereum/EIPs/issues/20 +.*/ + +pragma solidity ^0.5.8; + +import "../EIP20NonStandardInterface.sol"; + +// Note: the throw harness here always throws for errors, which is more realistic and useful +// for JavaScript tests. For Solidity tests, use: EIP20NonStandardReturnHarness. +contract EIP20NonStandardThrowHarness is EIP20NonStandardInterface { + + uint256 constant private MAX_UINT256 = 2**256 - 1; + uint256 public totalSupply; + mapping (address => uint256) public balances; + mapping (address => mapping (address => uint256)) public allowed; + + /* + To support testing, we can specify addresses for which transferFrom should fail and return false. + See `harnessSetFailTransferFromAddress` + */ + mapping (address => bool) public failTransferFromAddresses; + + /* + To support testing, we allow the contract to always fail `transfer`. + */ + mapping (address => bool) public failTransferToAddresses; + + + /* + NOTE: + The following variables are OPTIONAL vanities. One does not have to include them. + They allow one to customise the token contract & in no way influences the core functionality. + Some wallets/interfaces might not even bother to look at this information. + */ + string public name; //fancy name: eg Simon Bucks + uint8 public decimals; //How many decimals to show. + string public symbol; //An identifier: eg SBX + + constructor( + uint256 _initialAmount, + string memory _tokenName, + uint8 _decimalUnits, + string memory _tokenSymbol + ) public { + balances[msg.sender] = _initialAmount; // Give the creator all initial tokens + totalSupply = _initialAmount; // Update total supply + name = _tokenName; // Set the name for display purposes + decimals = _decimalUnits; // Amount of decimals for display purposes + symbol = _tokenSymbol; // Set the symbol for display purposes + } + + + /** + * @dev Specify `address, true` to cause transfers from address to fail. + * Once an address has been marked for failure it can be cleared by + * with `address, false` + */ + function harnessSetFailTransferFromAddress(address _from, bool _fail) public { + failTransferFromAddresses[_from] = _fail; + } + + /** + * @dev Specify `address, true` to cause transfers to address to fail. + * Once an address has been marked for failure it can be cleared by + * with `address, false` + */ + function harnessSetFailTransferToAddress(address _to, bool _fail) public { + failTransferToAddresses[_to] = _fail; + } + + function harnessSetBalance(address _account, uint _amount) public { + balances[_account] = _amount; + } + + function transfer(address _to, uint256 _value) public { + require(balances[msg.sender] >= _value); + + // Added for testing purposes + if (failTransferToAddresses[_to]) { + revert(); + } + + balances[msg.sender] -= _value; + balances[_to] += _value; + emit Transfer(msg.sender, _to, _value); + } + + function transferFrom(address _from, address _to, uint256 _value) public { + // Added for testing purposes + if (_from == address(0)) { + revert(); + } + + // Added for testing purposes + if (failTransferFromAddresses[_from]) { + revert(); + } + + uint256 allowance = allowed[_from][msg.sender]; + require(balances[_from] >= _value && allowance >= _value); + balances[_to] += _value; + balances[_from] -= _value; + if (allowance < MAX_UINT256) { + allowed[_from][msg.sender] -= _value; + } + emit Transfer(_from, _to, _value); + } + + function balanceOf(address _owner) public view returns (uint256 balance) { + return balances[_owner]; + } + + function approve(address _spender, uint256 _value) public returns (bool success) { + allowed[msg.sender][_spender] = _value; + emit Approval(msg.sender, _spender, _value); + return true; + } + + function allowance(address _owner, address _spender) public view returns (uint256 remaining) { + return allowed[_owner][_spender]; + } +} diff --git a/test/contracts/ERC20.sol b/test/contracts/ERC20.sol new file mode 100644 index 000000000..221983108 --- /dev/null +++ b/test/contracts/ERC20.sol @@ -0,0 +1,15 @@ +pragma solidity ^0.5.8; + +import "./ERC20Basic.sol"; + +/** + * @title ERC20 interface + * @dev see https://github.com/ethereum/EIPs/issues/20 + */ +contract ERC20 is ERC20Basic { + function allowance(address owner, address spender) public view returns (uint256); + function transferFrom(address from, address to, uint256 value) public returns (bool); + function approve(address spender, uint256 value) public returns (bool); + + event Approval(address indexed owner, address indexed spender, uint256 value); +} \ No newline at end of file diff --git a/test/contracts/ERC20Basic.sol b/test/contracts/ERC20Basic.sol new file mode 100644 index 000000000..ba4cbd4d4 --- /dev/null +++ b/test/contracts/ERC20Basic.sol @@ -0,0 +1,14 @@ +pragma solidity ^0.5.8; + + +/** + * @title ERC20Basic + * @dev Simpler version of ERC20 interface + * See https://github.com/ethereum/EIPs/issues/179 + */ +contract ERC20Basic { + function totalSupply() public view returns (uint256); + function balanceOf(address who) public view returns (uint256); + function transfer(address to, uint256 value) public returns (bool); + event Transfer(address indexed from, address indexed to, uint256 value); +} \ No newline at end of file diff --git a/test/contracts/ERC20BasicNS.sol b/test/contracts/ERC20BasicNS.sol new file mode 100644 index 000000000..5aadeb652 --- /dev/null +++ b/test/contracts/ERC20BasicNS.sol @@ -0,0 +1,13 @@ +pragma solidity ^0.5.8; + +/** + * @title ERC20BasicNS (Non-Standard) + * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` + * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca + */ +contract ERC20BasicNS { + function totalSupply() public view returns (uint256); + function balanceOf(address who) public view returns (uint256); + function transfer(address to, uint256 value) public; + event Transfer(address indexed from, address indexed to, uint256 value); +} \ No newline at end of file diff --git a/test/contracts/ERC20NS.sol b/test/contracts/ERC20NS.sol new file mode 100644 index 000000000..03486c239 --- /dev/null +++ b/test/contracts/ERC20NS.sol @@ -0,0 +1,16 @@ +pragma solidity ^0.5.8; + +import "./ERC20BasicNS.sol"; + +/** + * @title ERC20 interface (non-standard) + * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` + * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca + */ +contract ERC20NS is ERC20BasicNS { + function allowance(address owner, address spender) public view returns (uint256); + function transferFrom(address from, address to, uint256 value) public; + function approve(address spender, uint256 value) public returns (bool); + + event Approval(address indexed owner, address indexed spender, uint256 value); +} \ No newline at end of file diff --git a/test/contracts/ERC20NonView.sol b/test/contracts/ERC20NonView.sol new file mode 100644 index 000000000..34abed289 --- /dev/null +++ b/test/contracts/ERC20NonView.sol @@ -0,0 +1,196 @@ +pragma solidity ^0.5.8; + +import "./SafeMath.sol"; + +/** + * @title Standard ERC20 token with nothing as a "view" + * + * @dev Implementation of the basic standard token. + * https://eips.ethereum.org/EIPS/eip-20 + * Originally based on code by FirstBlood: + * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol + * + * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for + * all accounts just by listening to said events. Note that this isn't required by the specification, and other + * compliant implementations may not do it. + */ +contract ERC20NonView { + event Transfer(address indexed from, address indexed to, uint256 value); + + event Approval(address indexed owner, address indexed spender, uint256 value); + + using SafeMath for uint256; + + mapping (address => uint256) public _balances; + + mapping (address => mapping (address => uint256)) public _allowed; + + uint256 public _totalSupply; + + /** + * @dev Total number of tokens in existence + */ + function totalSupply() public returns (uint256) { + _totalSupply = _totalSupply; + return _totalSupply; + } + + /** + * @dev Gets the balance of the specified address. + * @param owner The address to query the balance of. + * @return A uint256 representing the amount owned by the passed address. + */ + function balanceOf(address owner) public returns (uint256) { + _totalSupply = _totalSupply; + return _balances[owner]; + } + + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + * @param owner address The address which owns the funds. + * @param spender address The address which will spend the funds. + * @return A uint256 specifying the amount of tokens still available for the spender. + */ + function allowance(address owner, address spender) public returns (uint256) { + _totalSupply = _totalSupply; + return _allowed[owner][spender]; + } + + /** + * @dev Transfer token to a specified address + * @param to The address to transfer to. + * @param value The amount to be transferred. + */ + function transfer(address to, uint256 value) public returns (bool) { + _transfer(msg.sender, to, value); + return true; + } + + /** + * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. + * 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 + * @param spender The address which will spend the funds. + * @param value The amount of tokens to be spent. + */ + function approve(address spender, uint256 value) public returns (bool) { + _approve(msg.sender, spender, value); + return true; + } + + /** + * @dev Transfer tokens from one address to another. + * Note that while this function emits an Approval event, this is not required as per the specification, + * and other compliant implementations may not emit the event. + * @param from address The address which you want to send tokens from + * @param to address The address which you want to transfer to + * @param value uint256 the amount of tokens to be transferred + */ + function transferFrom(address from, address to, uint256 value) public returns (bool) { + _transfer(from, to, value); + _approve(from, msg.sender, _allowed[from][msg.sender].sub(value)); + return true; + } + + /** + * @dev Increase the amount of tokens that an owner allowed to a spender. + * approve should be called when _allowed[msg.sender][spender] == 0. To increment + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * Emits an Approval event. + * @param spender The address which will spend the funds. + * @param addedValue The amount of tokens to increase the allowance by. + */ + function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { + _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue)); + return true; + } + + /** + * @dev Decrease the amount of tokens that an owner allowed to a spender. + * approve should be called when _allowed[msg.sender][spender] == 0. To decrement + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * Emits an Approval event. + * @param spender The address which will spend the funds. + * @param subtractedValue The amount of tokens to decrease the allowance by. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { + _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue)); + return true; + } + + /** + * @dev Transfer token for a specified addresses + * @param from The address to transfer from. + * @param to The address to transfer to. + * @param value The amount to be transferred. + */ + function _transfer(address from, address to, uint256 value) internal { + require(to != address(0)); + + _balances[from] = _balances[from].sub(value); + _balances[to] = _balances[to].add(value); + emit Transfer(from, to, value); + } + + /** + * @dev Internal function that mints an amount of the token and assigns it to + * an account. This encapsulates the modification of balances such that the + * proper events are emitted. + * @param account The account that will receive the created tokens. + * @param value The amount that will be created. + */ + function _mint(address account, uint256 value) internal { + require(account != address(0)); + + _totalSupply = _totalSupply.add(value); + _balances[account] = _balances[account].add(value); + emit Transfer(address(0), account, value); + } + + /** + * @dev Internal function that burns an amount of the token of a given + * account. + * @param account The account whose tokens will be burnt. + * @param value The amount that will be burnt. + */ + function _burn(address account, uint256 value) internal { + require(account != address(0)); + + _totalSupply = _totalSupply.sub(value); + _balances[account] = _balances[account].sub(value); + emit Transfer(account, address(0), value); + } + + /** + * @dev Approve an address to spend another addresses' tokens. + * @param owner The address that owns the tokens. + * @param spender The address that will spend the tokens. + * @param value The number of tokens that can be spent. + */ + function _approve(address owner, address spender, uint256 value) internal { + require(spender != address(0)); + require(owner != address(0)); + + _allowed[owner][spender] = value; + emit Approval(owner, spender, value); + } + + /** + * @dev Internal function that burns an amount of the token of a given + * account, deducting from the sender's allowance for said account. Uses the + * internal burn function. + * Emits an Approval event (reflecting the reduced allowance). + * @param account The account whose tokens will be burnt. + * @param value The amount that will be burnt. + */ + function _burnFrom(address account, uint256 value) internal { + _burn(account, value); + _approve(account, msg.sender, _allowed[account][msg.sender].sub(value)); + } +} diff --git a/test/contracts/EchoTypesComptroller.sol b/test/contracts/EchoTypesComptroller.sol new file mode 100644 index 000000000..fb605864b --- /dev/null +++ b/test/contracts/EchoTypesComptroller.sol @@ -0,0 +1,31 @@ +pragma solidity ^0.5.8; + +import "../ComptrollerStorage.sol"; +import "../Unitroller.sol"; + +contract EchoTypesComptroller is UnitrollerAdminStorage { + + function stringy(string memory s) public pure returns(string memory) { + return s; + } + + function addresses(address a) public pure returns(address) { + return a; + } + + function booly(bool b) public pure returns(bool) { + return b; + } + + function listOInts(uint[] memory u) public pure returns(uint[] memory) { + return u; + } + + function reverty() public pure { + require(false, "gotcha sucka"); + } + + function becomeBrains(address payable unitroller) public { + Unitroller(unitroller)._acceptImplementation(); + } +} diff --git a/test/contracts/EvilToken.sol b/test/contracts/EvilToken.sol new file mode 100644 index 000000000..34cb0c414 --- /dev/null +++ b/test/contracts/EvilToken.sol @@ -0,0 +1,59 @@ +pragma solidity ^0.5.8; + +import "./StandardToken.sol"; + +/** + * @title The Compound Evil Test Token + * @author Compound + * @notice A simple test token that fails certain operations + */ +contract EvilToken is StandardToken { + string public name; + string public symbol; + uint8 public decimals; + bool public fail; + + constructor(uint256 _initialAmount, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol) public { + totalSupply_ = _initialAmount; + balances[msg.sender] = _initialAmount; + name = _tokenName; + symbol = _tokenSymbol; + decimals = _decimalUnits; + fail = true; + } + + function setFail(bool _fail) public { + fail = _fail; + } + + /** + * @dev Arbitrarily adds tokens to any account + */ + function allocateTo(address _owner, uint256 value) public { + balances[_owner] += value; + totalSupply_ += value; + emit Transfer(address(this), _owner, value); + } + + /** + * @dev Fail to transfer + */ + function transfer(address to, uint256 value) public returns (bool) { + if (fail) { + return false; + } + + return super.transfer(to, value); + } + + /** + * @dev Fail to transfer from + */ + function transferFrom(address from, address to, uint256 value) public returns (bool) { + if (fail) { + return false; + } + + return super.transferFrom(from, to, value); + } +} diff --git a/test/contracts/FalseMarkerMethodComptroller.sol b/test/contracts/FalseMarkerMethodComptroller.sol new file mode 100644 index 000000000..e8496bc30 --- /dev/null +++ b/test/contracts/FalseMarkerMethodComptroller.sol @@ -0,0 +1,6 @@ +pragma solidity ^0.5.8; +import "./BoolComptroller.sol"; + +contract FalseMarkerMethodComptroller is BoolComptroller { + bool public isComptroller = false; +} diff --git a/test/contracts/FalseMarkerMethodInterestRateModel.sol b/test/contracts/FalseMarkerMethodInterestRateModel.sol new file mode 100644 index 000000000..ccf324e6b --- /dev/null +++ b/test/contracts/FalseMarkerMethodInterestRateModel.sol @@ -0,0 +1,36 @@ +pragma solidity ^0.5.8; + +import "../InterestRateModel.sol"; + +/** + * @title Implements the interest rate model marker function but returns false + * @author Compound + */ +contract FalseMarkerMethodInterestRateModel is InterestRateModel { + /** + * For exhaustive testing, this contract implements the marker function but returns false instead of the intended true + */ + bool public constant isInterestRateModel = false; + + uint borrowRate; + + constructor(uint borrowRate_) public { + borrowRate = borrowRate_; + } + + /** + * @notice Gets the current borrow interest rate based on the given asset, total cash and total borrows + * @dev The return value should be scaled by 1e18, thus a return value of + * `(true, 1000000000000)` implies an interest rate of 0.000001% *per block*. + * @param _cash The total cash of the asset in the CToken + * @param _borrows The total borrows of the asset in the CToken + * @param _reserves The total reserves of the asset in the CToken + * @return Success or failure and the borrow interest rate per block scaled by 1e18 + */ + function getBorrowRate(uint _cash, uint _borrows, uint _reserves) view public returns (uint, uint) { + _cash; // unused + _borrows; // unused + _reserves; // unused + return (0, borrowRate); + } +} \ No newline at end of file diff --git a/test/contracts/FaucetNonStandardToken.sol b/test/contracts/FaucetNonStandardToken.sol new file mode 100644 index 000000000..389198fc5 --- /dev/null +++ b/test/contracts/FaucetNonStandardToken.sol @@ -0,0 +1,31 @@ +pragma solidity ^0.5.8; + +import "./NonStandardToken.sol"; + +/** + * @title The Compound Faucet Test Token + * @author Compound + * @notice A simple test token that lets anyone get more of it. + */ +contract FaucetNonStandardToken is NonStandardToken { + string public name; + string public symbol; + uint8 public decimals; + + constructor(uint256 _initialAmount, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol) public { + totalSupply_ = _initialAmount; + balances[msg.sender] = _initialAmount; + name = _tokenName; + symbol = _tokenSymbol; + decimals = _decimalUnits; + } + + /** + * @dev Arbitrarily adds tokens to any account + */ + function allocateTo(address _owner, uint256 value) public { + balances[_owner] += value; + totalSupply_ += value; + emit Transfer(address(this), _owner, value); + } +} diff --git a/test/contracts/FaucetToken.sol b/test/contracts/FaucetToken.sol new file mode 100644 index 000000000..8d38a702e --- /dev/null +++ b/test/contracts/FaucetToken.sol @@ -0,0 +1,31 @@ +pragma solidity ^0.5.8; + +import "./StandardToken.sol"; + +/** + * @title The Compound Faucet Test Token + * @author Compound + * @notice A simple test token that lets anyone get more of it. + */ +contract FaucetToken is StandardToken { + string public name; + string public symbol; + uint8 public decimals; + + constructor(uint256 _initialAmount, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol) public { + totalSupply_ = _initialAmount; + balances[msg.sender] = _initialAmount; + name = _tokenName; + symbol = _tokenSymbol; + decimals = _decimalUnits; + } + + /** + * @dev Arbitrarily adds tokens to any account + */ + function allocateTo(address _owner, uint256 value) public { + balances[_owner] += value; + totalSupply_ += value; + emit Transfer(address(this), _owner, value); + } +} diff --git a/test/contracts/FaucetTokenReEntrantHarness.sol b/test/contracts/FaucetTokenReEntrantHarness.sol new file mode 100644 index 000000000..d98e2d2b7 --- /dev/null +++ b/test/contracts/FaucetTokenReEntrantHarness.sol @@ -0,0 +1,75 @@ +pragma solidity ^0.5.8; + +import "./ERC20NonView.sol"; + +/** + * @title The Compound Faucet Re-Entrant Test Token + * @author Compound + * @notice A test token that is malicious and tries to re-enter callers + */ +contract FaucetTokenReEntrantHarness is ERC20NonView { + string public name; + string public symbol; + uint8 public decimals; + bytes public reEntryCallData; + string public reEntryFun; + + constructor(uint256 _initialAmount, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol, bytes memory _reEntryCallData, string memory _reEntryFun) public { + _totalSupply = _initialAmount; + _balances[msg.sender] = _initialAmount; + name = _tokenName; + symbol = _tokenSymbol; + decimals = _decimalUnits; + reEntryCallData = _reEntryCallData; + reEntryFun = _reEntryFun; + } + + modifier reEnter(string memory funName) { + string memory _reEntryFun = reEntryFun; + if (compareStrings(_reEntryFun, funName)) { + reEntryFun = ""; // Clear re-entry fun + (bool _res, bytes memory _ret) = msg.sender.call(reEntryCallData); + _res; // unused + _ret; // unused + } + + _; + } + + function compareStrings(string memory a, string memory b) internal pure returns (bool) { + return keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b))); + } + + /** + * @dev Arbitrarily adds tokens to any account + */ + function allocateTo(address _owner, uint256 value) public { + _balances[_owner] += value; + _totalSupply += value; + emit Transfer(address(this), _owner, value); + } + + function totalSupply() public reEnter("totalSupply") returns (uint256) { + return super.totalSupply(); + } + + function balanceOf(address owner) public reEnter("balanceOf") returns (uint256 balance) { + return super.balanceOf(owner); + } + + function transfer(address dst, uint256 amount) public reEnter("transfer") returns (bool success) { + return super.transfer(dst, amount); + } + + function transferFrom(address src, address dst, uint256 amount) public reEnter("transferFrom") returns (bool success) { + return super.transferFrom(src, dst, amount); + } + + function approve(address spender, uint256 amount) public reEnter("approve") returns (bool success) { + return super.approve(spender, amount); + } + + function allowance(address owner, address spender) public reEnter("allowance") returns (uint256 remaining) { + return super.allowance(owner, spender); + } +} diff --git a/test/contracts/FixedPriceOracle.sol b/test/contracts/FixedPriceOracle.sol new file mode 100644 index 000000000..8b05d300a --- /dev/null +++ b/test/contracts/FixedPriceOracle.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.5.8; + +import "../PriceOracle.sol"; + +contract FixedPriceOracle is PriceOracle { + uint public price; + bool public constant isPriceOracle = true; + + constructor(uint _price) public { + price = _price; + } + + function getUnderlyingPrice(CToken cToken) public view returns (uint) { + cToken; + return price; + } + + function assetPrices(address asset) public view returns (uint) { + asset; + return price; + } +} diff --git a/test/contracts/InterestRateModelHarness.sol b/test/contracts/InterestRateModelHarness.sol new file mode 100644 index 000000000..5e23f51aa --- /dev/null +++ b/test/contracts/InterestRateModelHarness.sol @@ -0,0 +1,37 @@ +pragma solidity ^0.5.8; + +import "../InterestRateModel.sol"; + +/** + * @title An Interest Rate Model for tests that can be instructed to return a failure instead of doing a calculation + * @author Compound + */ +contract InterestRateModelHarness is InterestRateModel { + bool public constant isInterestRateModel = true; + uint public constant opaqueBorrowFailureCode = 20; + bool public failBorrowRate; + uint public borrowRate; + + constructor(uint borrowRate_) public { + borrowRate = borrowRate_; + } + + function setFailBorrowRate(bool failBorrowRate_) public { + failBorrowRate = failBorrowRate_; + } + + function setBorrowRate(uint borrowRate_) public { + borrowRate = borrowRate_; + } + + function getBorrowRate(uint _cash, uint _borrows, uint _reserves) public view returns (uint, uint) { + _cash; // unused + _borrows; // unused + _reserves; // unused + + if (failBorrowRate) { + return (opaqueBorrowFailureCode, 0); + } + return (0, borrowRate); + } +} \ No newline at end of file diff --git a/test/contracts/MathHelpers.sol b/test/contracts/MathHelpers.sol new file mode 100644 index 000000000..c9224965f --- /dev/null +++ b/test/contracts/MathHelpers.sol @@ -0,0 +1,12 @@ +pragma solidity ^0.5.8; + +contract MathHelpers { + + /* + * @dev Creates a number like 15e16 as a uint256 from scientific(15, 16). + */ + function scientific(uint val, uint expTen) pure internal returns (uint) { + return val * ( 10 ** expTen ); + } + +} \ No newline at end of file diff --git a/test/contracts/NonStandardToken.sol b/test/contracts/NonStandardToken.sol new file mode 100644 index 000000000..d51837eca --- /dev/null +++ b/test/contracts/NonStandardToken.sol @@ -0,0 +1,122 @@ +pragma solidity ^0.5.8; + +import "./BasicTokenNS.sol"; +import "./ERC20NS.sol"; + + +/** + * @title Non-Standard ERC20 token + * + * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` + * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca + * Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol + */ +contract NonStandardToken is ERC20NS, BasicTokenNS { + + mapping (address => mapping (address => uint256)) internal allowed; + + + /** + * @dev Transfer tokens from one address to another + * @param _from address The address which you want to send tokens from + * @param _to address The address which you want to transfer to + * @param _value uint256 the amount of tokens to be transferred + */ + function transferFrom( + address _from, + address _to, + uint256 _value + ) + public + { + require(_to != address(0)); + require(_value <= balances[_from]); + require(_value <= allowed[_from][msg.sender]); + + balances[_from] = balances[_from].sub(_value); + balances[_to] = balances[_to].add(_value); + allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); + emit Transfer(_from, _to, _value); + } + + /** + * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. + * 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 + * @param _spender The address which will spend the funds. + * @param _value The amount of tokens to be spent. + */ + function approve(address _spender, uint256 _value) public returns (bool) { + allowed[msg.sender][_spender] = _value; + emit Approval(msg.sender, _spender, _value); + return true; + } + + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + * @param _owner address The address which owns the funds. + * @param _spender address The address which will spend the funds. + * @return A uint256 specifying the amount of tokens still available for the spender. + */ + function allowance( + address _owner, + address _spender + ) + public + view + returns (uint256) + { + return allowed[_owner][_spender]; + } + + /** + * @dev Increase the amount of tokens that an owner allowed to a spender. + * approve should be called when allowed[_spender] == 0. To increment + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _addedValue The amount of tokens to increase the allowance by. + */ + function increaseApproval( + address _spender, + uint256 _addedValue + ) + public + returns (bool) + { + allowed[msg.sender][_spender] = ( + allowed[msg.sender][_spender].add(_addedValue)); + emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); + return true; + } + + /** + * @dev Decrease the amount of tokens that an owner allowed to a spender. + * approve should be called when allowed[_spender] == 0. To decrement + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _subtractedValue The amount of tokens to decrease the allowance by. + */ + function decreaseApproval( + address _spender, + uint256 _subtractedValue + ) + public + returns (bool) + { + uint256 oldValue = allowed[msg.sender][_spender]; + if (_subtractedValue > oldValue) { + allowed[msg.sender][_spender] = 0; + } else { + allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); + } + emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); + return true; + } + +} \ No newline at end of file diff --git a/test/contracts/NotPriceOracle.sol b/test/contracts/NotPriceOracle.sol new file mode 100644 index 000000000..8503f6295 --- /dev/null +++ b/test/contracts/NotPriceOracle.sol @@ -0,0 +1,6 @@ +pragma solidity ^0.5.8; + +contract NotPriceOracle { + // marker function + bool public constant isPriceOracle = false; +} diff --git a/test/contracts/SafeMath.sol b/test/contracts/SafeMath.sol new file mode 100644 index 000000000..15cac29d1 --- /dev/null +++ b/test/contracts/SafeMath.sol @@ -0,0 +1,52 @@ +pragma solidity ^0.5.8; + + +/** + * @title SafeMath + * @dev Math operations with safety checks that throw on error + */ +library SafeMath { + + /** + * @dev Multiplies two numbers, throws on overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { + // Gas optimization: this is cheaper than asserting 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 + if (a == 0) { + return 0; + } + + c = a * b; + assert(c / a == b); + return c; + } + + /** + * @dev Integer division of two numbers, truncating the quotient. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + // uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return a / b; + } + + /** + * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + assert(b <= a); + return a - b; + } + + /** + * @dev Adds two numbers, throws on overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256 c) { + c = a + b; + assert(c >= a); + return c; + } +} \ No newline at end of file diff --git a/test/contracts/StandardToken.sol b/test/contracts/StandardToken.sol new file mode 100644 index 000000000..7865127e5 --- /dev/null +++ b/test/contracts/StandardToken.sol @@ -0,0 +1,124 @@ +pragma solidity ^0.5.8; + +import "./BasicToken.sol"; +import "./ERC20.sol"; + + +/** + * @title Standard ERC20 token + * + * @dev Implementation of the basic standard token. + * https://github.com/ethereum/EIPs/issues/20 + * Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol + */ +contract StandardToken is ERC20, BasicToken { + + mapping (address => mapping (address => uint256)) internal allowed; + + + /** + * @dev Transfer tokens from one address to another + * @param _from address The address which you want to send tokens from + * @param _to address The address which you want to transfer to + * @param _value uint256 the amount of tokens to be transferred + */ + function transferFrom( + address _from, + address _to, + uint256 _value + ) + public + returns (bool) + { + require(_to != address(0)); + require(_value <= balances[_from]); + require(_value <= allowed[_from][msg.sender]); + + balances[_from] = balances[_from].sub(_value); + balances[_to] = balances[_to].add(_value); + allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); + emit Transfer(_from, _to, _value); + return true; + } + + /** + * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. + * 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 + * @param _spender The address which will spend the funds. + * @param _value The amount of tokens to be spent. + */ + function approve(address _spender, uint256 _value) public returns (bool) { + allowed[msg.sender][_spender] = _value; + emit Approval(msg.sender, _spender, _value); + return true; + } + + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + * @param _owner address The address which owns the funds. + * @param _spender address The address which will spend the funds. + * @return A uint256 specifying the amount of tokens still available for the spender. + */ + function allowance( + address _owner, + address _spender + ) + public + view + returns (uint256) + { + return allowed[_owner][_spender]; + } + + /** + * @dev Increase the amount of tokens that an owner allowed to a spender. + * approve should be called when allowed[_spender] == 0. To increment + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _addedValue The amount of tokens to increase the allowance by. + */ + function increaseApproval( + address _spender, + uint256 _addedValue + ) + public + returns (bool) + { + allowed[msg.sender][_spender] = ( + allowed[msg.sender][_spender].add(_addedValue)); + emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); + return true; + } + + /** + * @dev Decrease the amount of tokens that an owner allowed to a spender. + * approve should be called when allowed[_spender] == 0. To decrement + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _subtractedValue The amount of tokens to decrease the allowance by. + */ + function decreaseApproval( + address _spender, + uint256 _subtractedValue + ) + public + returns (bool) + { + uint256 oldValue = allowed[msg.sender][_spender]; + if (_subtractedValue > oldValue) { + allowed[msg.sender][_spender] = 0; + } else { + allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); + } + emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); + return true; + } + +} \ No newline at end of file diff --git a/test/contracts/WBTC.sol b/test/contracts/WBTC.sol new file mode 100644 index 000000000..f61da7133 --- /dev/null +++ b/test/contracts/WBTC.sol @@ -0,0 +1,672 @@ +/** + *Submitted for verification at Etherscan.io on 2018-11-24 +*/ + +pragma solidity ^0.5.8; + +// File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol + +/** + * @title ERC20Basic + * @dev Simpler version of ERC20 interface + * See https://github.com/ethereum/EIPs/issues/179 + */ +contract ERC20Basic { + function totalSupply() public view returns (uint256); + function balanceOf(address _who) public view returns (uint256); + function transfer(address _to, uint256 _value) public returns (bool); + event Transfer(address indexed from, address indexed to, uint256 value); +} + +// File: openzeppelin-solidity/contracts/math/SafeMath.sol + +/** + * @title SafeMath + * @dev Math operations with safety checks that throw on error + */ +library SafeMath { + + /** + * @dev Multiplies two numbers, throws on overflow. + */ + function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) { + // Gas optimization: this is cheaper than asserting 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 + if (_a == 0) { + return 0; + } + + c = _a * _b; + assert(c / _a == _b); + return c; + } + + /** + * @dev Integer division of two numbers, truncating the quotient. + */ + function div(uint256 _a, uint256 _b) internal pure returns (uint256) { + // assert(_b > 0); // Solidity automatically throws when dividing by 0 + // uint256 c = _a / _b; + // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold + return _a / _b; + } + + /** + * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). + */ + function sub(uint256 _a, uint256 _b) internal pure returns (uint256) { + assert(_b <= _a); + return _a - _b; + } + + /** + * @dev Adds two numbers, throws on overflow. + */ + function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) { + c = _a + _b; + assert(c >= _a); + return c; + } +} + +// File: openzeppelin-solidity/contracts/token/ERC20/BasicToken.sol + +/** + * @title Basic token + * @dev Basic version of StandardToken, with no allowances. + */ +contract BasicToken is ERC20Basic { + using SafeMath for uint256; + + mapping(address => uint256) internal balances; + + uint256 internal totalSupply_; + + /** + * @dev Total number of tokens in existence + */ + function totalSupply() public view returns (uint256) { + return totalSupply_; + } + + /** + * @dev Transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) public returns (bool) { + require(_value <= balances[msg.sender]); + require(_to != address(0)); + + balances[msg.sender] = balances[msg.sender].sub(_value); + balances[_to] = balances[_to].add(_value); + emit Transfer(msg.sender, _to, _value); + return true; + } + + /** + * @dev Gets the balance of the specified address. + * @param _owner The address to query the the balance of. + * @return An uint256 representing the amount owned by the passed address. + */ + function balanceOf(address _owner) public view returns (uint256) { + return balances[_owner]; + } + +} + +// File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol + +/** + * @title ERC20 interface + * @dev see https://github.com/ethereum/EIPs/issues/20 + */ +contract ERC20 is ERC20Basic { + function allowance(address _owner, address _spender) + public view returns (uint256); + + function transferFrom(address _from, address _to, uint256 _value) + public returns (bool); + + function approve(address _spender, uint256 _value) public returns (bool); + event Approval( + address indexed owner, + address indexed spender, + uint256 value + ); +} + +// File: openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol + +/** + * @title Standard ERC20 token + * + * @dev Implementation of the basic standard token. + * https://github.com/ethereum/EIPs/issues/20 + * Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol + */ +contract StandardToken is ERC20, BasicToken { + + mapping (address => mapping (address => uint256)) internal allowed; + + + /** + * @dev Transfer tokens from one address to another + * @param _from address The address which you want to send tokens from + * @param _to address The address which you want to transfer to + * @param _value uint256 the amount of tokens to be transferred + */ + function transferFrom( + address _from, + address _to, + uint256 _value + ) + public + returns (bool) + { + require(_value <= balances[_from]); + require(_value <= allowed[_from][msg.sender]); + require(_to != address(0)); + + balances[_from] = balances[_from].sub(_value); + balances[_to] = balances[_to].add(_value); + allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); + emit Transfer(_from, _to, _value); + return true; + } + + /** + * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. + * 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 + * @param _spender The address which will spend the funds. + * @param _value The amount of tokens to be spent. + */ + function approve(address _spender, uint256 _value) public returns (bool) { + allowed[msg.sender][_spender] = _value; + emit Approval(msg.sender, _spender, _value); + return true; + } + + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + * @param _owner address The address which owns the funds. + * @param _spender address The address which will spend the funds. + * @return A uint256 specifying the amount of tokens still available for the spender. + */ + function allowance( + address _owner, + address _spender + ) + public + view + returns (uint256) + { + return allowed[_owner][_spender]; + } + + /** + * @dev Increase the amount of tokens that an owner allowed to a spender. + * approve should be called when allowed[_spender] == 0. To increment + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _addedValue The amount of tokens to increase the allowance by. + */ + function increaseApproval( + address _spender, + uint256 _addedValue + ) + public + returns (bool) + { + allowed[msg.sender][_spender] = ( + allowed[msg.sender][_spender].add(_addedValue)); + emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); + return true; + } + + /** + * @dev Decrease the amount of tokens that an owner allowed to a spender. + * approve should be called when allowed[_spender] == 0. To decrement + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _subtractedValue The amount of tokens to decrease the allowance by. + */ + function decreaseApproval( + address _spender, + uint256 _subtractedValue + ) + public + returns (bool) + { + uint256 oldValue = allowed[msg.sender][_spender]; + if (_subtractedValue >= oldValue) { + allowed[msg.sender][_spender] = 0; + } else { + allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); + } + emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); + return true; + } + +} + +// File: openzeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol + +/** + * @title DetailedERC20 token + * @dev The decimals are only for visualization purposes. + * All the operations are done using the smallest and indivisible token unit, + * just as on Ethereum all the operations are done in wei. + */ +contract DetailedERC20 is ERC20 { + string public name; + string public symbol; + uint8 public decimals; + + constructor(string memory _name, string memory _symbol, uint8 _decimals) public { + name = _name; + symbol = _symbol; + decimals = _decimals; + } +} + +// File: openzeppelin-solidity/contracts/ownership/Ownable.sol + +/** + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ +contract Ownable { + address public owner; + + + event OwnershipRenounced(address indexed previousOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); + + + /** + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() public { + owner = msg.sender; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipRenounced(owner); + owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param _newOwner The address to transfer ownership to. + */ + function transferOwnership(address _newOwner) public onlyOwner { + _transferOwnership(_newOwner); + } + + /** + * @dev Transfers control of the contract to a newOwner. + * @param _newOwner The address to transfer ownership to. + */ + function _transferOwnership(address _newOwner) internal { + require(_newOwner != address(0)); + emit OwnershipTransferred(owner, _newOwner); + owner = _newOwner; + } +} + +// File: openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol + +/** + * @title Mintable token + * @dev Simple ERC20 Token example, with mintable token creation + * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol + */ +contract MintableToken is StandardToken, Ownable { + event Mint(address indexed to, uint256 amount); + event MintFinished(); + + bool public mintingFinished = false; + + + modifier canMint() { + require(!mintingFinished); + _; + } + + modifier hasMintPermission() { + require(msg.sender == owner); + _; + } + + /** + * @dev Function to mint tokens + * @param _to The address that will receive the minted tokens. + * @param _amount The amount of tokens to mint. + * @return A boolean that indicates if the operation was successful. + */ + function mint( + address _to, + uint256 _amount + ) + public + hasMintPermission + canMint + returns (bool) + { + totalSupply_ = totalSupply_.add(_amount); + balances[_to] = balances[_to].add(_amount); + emit Mint(_to, _amount); + emit Transfer(address(0), _to, _amount); + return true; + } + + /** + * @dev Function to stop minting new tokens. + * @return True if the operation was successful. + */ + function finishMinting() public onlyOwner canMint returns (bool) { + mintingFinished = true; + emit MintFinished(); + return true; + } +} + +// File: openzeppelin-solidity/contracts/token/ERC20/BurnableToken.sol + +/** + * @title Burnable Token + * @dev Token that can be irreversibly burned (destroyed). + */ +contract BurnableToken is BasicToken { + + event Burn(address indexed burner, uint256 value); + + /** + * @dev Burns a specific amount of tokens. + * @param _value The amount of token to be burned. + */ + function burn(uint256 _value) public { + _burn(msg.sender, _value); + } + + function _burn(address _who, uint256 _value) internal { + require(_value <= balances[_who]); + // no need to require value <= totalSupply, since that would imply the + // sender's balance is greater than the totalSupply, which *should* be an assertion failure + + balances[_who] = balances[_who].sub(_value); + totalSupply_ = totalSupply_.sub(_value); + emit Burn(_who, _value); + emit Transfer(_who, address(0), _value); + } +} + +// File: openzeppelin-solidity/contracts/lifecycle/Pausable.sol + +/** + * @title Pausable + * @dev Base contract which allows children to implement an emergency stop mechanism. + */ +contract Pausable is Ownable { + event Pause(); + event Unpause(); + + bool public paused = false; + + + /** + * @dev Modifier to make a function callable only when the contract is not paused. + */ + modifier whenNotPaused() { + require(!paused); + _; + } + + /** + * @dev Modifier to make a function callable only when the contract is paused. + */ + modifier whenPaused() { + require(paused); + _; + } + + /** + * @dev called by the owner to pause, triggers stopped state + */ + function pause() public onlyOwner whenNotPaused { + paused = true; + emit Pause(); + } + + /** + * @dev called by the owner to unpause, returns to normal state + */ + function unpause() public onlyOwner whenPaused { + paused = false; + emit Unpause(); + } +} + +// File: openzeppelin-solidity/contracts/token/ERC20/PausableToken.sol + +/** + * @title Pausable token + * @dev StandardToken modified with pausable transfers. + **/ +contract PausableToken is StandardToken, Pausable { + + function transfer( + address _to, + uint256 _value + ) + public + whenNotPaused + returns (bool) + { + return super.transfer(_to, _value); + } + + function transferFrom( + address _from, + address _to, + uint256 _value + ) + public + whenNotPaused + returns (bool) + { + return super.transferFrom(_from, _to, _value); + } + + function approve( + address _spender, + uint256 _value + ) + public + whenNotPaused + returns (bool) + { + return super.approve(_spender, _value); + } + + function increaseApproval( + address _spender, + uint _addedValue + ) + public + whenNotPaused + returns (bool success) + { + return super.increaseApproval(_spender, _addedValue); + } + + function decreaseApproval( + address _spender, + uint _subtractedValue + ) + public + whenNotPaused + returns (bool success) + { + return super.decreaseApproval(_spender, _subtractedValue); + } +} + +// File: openzeppelin-solidity/contracts/ownership/Claimable.sol + +/** + * @title Claimable + * @dev Extension for the Ownable contract, where the ownership needs to be claimed. + * This allows the new owner to accept the transfer. + */ +contract Claimable is Ownable { + address public pendingOwner; + + /** + * @dev Modifier throws if called by any account other than the pendingOwner. + */ + modifier onlyPendingOwner() { + require(msg.sender == pendingOwner); + _; + } + + /** + * @dev Allows the current owner to set the pendingOwner address. + * @param newOwner The address to transfer ownership to. + */ + function transferOwnership(address newOwner) public onlyOwner { + pendingOwner = newOwner; + } + + /** + * @dev Allows the pendingOwner address to finalize the transfer. + */ + function claimOwnership() public onlyPendingOwner { + emit OwnershipTransferred(owner, pendingOwner); + owner = pendingOwner; + pendingOwner = address(0); + } +} + +// File: openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure. + * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + function safeTransfer( + ERC20Basic _token, + address _to, + uint256 _value + ) + internal + { + require(_token.transfer(_to, _value)); + } + + function safeTransferFrom( + ERC20 _token, + address _from, + address _to, + uint256 _value + ) + internal + { + require(_token.transferFrom(_from, _to, _value)); + } + + function safeApprove( + ERC20 _token, + address _spender, + uint256 _value + ) + internal + { + require(_token.approve(_spender, _value)); + } +} + +// File: openzeppelin-solidity/contracts/ownership/CanReclaimToken.sol + +/** + * @title Contracts that should be able to recover tokens + * @author SylTi + * @dev This allow a contract to recover any ERC20 token received in a contract by transferring the balance to the contract owner. + * This will prevent any accidental loss of tokens. + */ +contract CanReclaimToken is Ownable { + using SafeERC20 for ERC20Basic; + + /** + * @dev Reclaim all ERC20Basic compatible tokens + * @param _token ERC20Basic The address of the token contract + */ + function reclaimToken(ERC20Basic _token) external onlyOwner { + uint256 balance = _token.balanceOf(address(this)); + _token.safeTransfer(owner, balance); + } + +} + +// File: contracts/utils/OwnableContract.sol + +// empty block is used as this contract just inherits others. +contract OwnableContract is CanReclaimToken, Claimable { } /* solhint-disable-line no-empty-blocks */ + +// File: contracts/token/WBTC.sol + +contract WBTCToken is StandardToken, DetailedERC20("Wrapped BTC", "WBTC", 8), + MintableToken, BurnableToken, PausableToken, OwnableContract { + + function burn(uint value) public onlyOwner { + super.burn(value); + } + + function finishMinting() public onlyOwner returns (bool) { + return false; + } + + function renounceOwnership() public onlyOwner { + revert("renouncing ownership is blocked"); + } + + /** + * @dev Arbitrarily adds tokens to any account + */ + function allocateTo(address _owner, uint256 value) public { + balances[_owner] += value; + totalSupply_ += value; + emit Transfer(address(this), _owner, value); + } +} diff --git a/truffle.js b/truffle.js new file mode 100644 index 000000000..29543900a --- /dev/null +++ b/truffle.js @@ -0,0 +1,88 @@ +"use strict"; + +const Web3 = require("web3"); +const fs = require('fs'); +const path = require('path'); + +const networks = { + rinkeby: 4, + kovan: 42, + ropsten: 3, + mainnet: 1, + goerli: 5 +}; + +const infuraNetworks = Object.entries(networks).reduce((networks, [network, networkId]) => { + return { + ...networks, + [network]: { + provider: new Web3.providers.HttpProvider(`https://${network}.infura.io/`), + network_id: networkId + } + }; +}, {}); + +let mochaOptions = { + reporter: "mocha-multi-reporters", + reporterOptions: { + configFile: "reporterConfig.json" + } +}; + +if (process.env.NETWORK === 'coverage') { + mochaOptions = { + enableTimeouts: false, + grep: /@gas/, + invert: true + }; +} + +const development = { + host: "localhost", + port: 8545, + network_id: "*", + gas: 6700000, + gasPrice: 20000, +} + +const coverage = { // See example coverage settings at https://github.com/sc-forks/solidity-coverage + host: "localhost", + network_id: "*", + gas: 0xfffffffffff, + gasPrice: 0x01, + port: 8555 +}; + +const test = { + host: "localhost", + port: 8545, + network_id: "*", + gas: 20000000, + gasPrice: 20000 +}; + +process.env[`development_opts`] = JSON.stringify(development); +process.env[`coverage_opts`] = JSON.stringify(coverage); +process.env[`test_opts`] = JSON.stringify(test); + +module.exports = { + networks: { + ...infuraNetworks, + development, + coverage, + test + }, + compilers: { + solc: { + version: "0.5.8", + settings: { + optimizer: { + enabled: true + } + } + } + }, + mocha: mochaOptions, + contracts_build_directory: process.env.CONTRACTS_BUILD_DIRECTORY || undefined, + build_directory: process.env.BUILD_DIRECTORY || undefined +}; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..deab9d16f --- /dev/null +++ b/yarn.lock @@ -0,0 +1,6179 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/runtime@^7.3.1": + version "7.5.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.4.tgz#cb7d1ad7c6d65676e66b47186577930465b5271b" + integrity sha512-Na84uwyImZZc3FKf4aUF1tysApzwf3p2yuFBIyBfbzT5glzKTdvYI4KVW4kcgjrzoGUjC7w3YyCHcJKaRxsr2Q== + dependencies: + regenerator-runtime "^0.13.2" + +"@resolver-engine/core@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@resolver-engine/core/-/core-0.2.1.tgz#0d71803f6d3b8cb2e9ed481a1bf0ca5f5256d0c0" + integrity sha512-nsLQHmPJ77QuifqsIvqjaF5B9aHnDzJjp73Q1z6apY3e9nqYrx4Dtowhpsf7Jwftg/XzVDEMQC+OzUBNTS+S1A== + dependencies: + debug "^3.1.0" + request "^2.85.0" + +"@resolver-engine/fs@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@resolver-engine/fs/-/fs-0.2.1.tgz#f98a308d77568cc02651d03636f46536b941b241" + integrity sha512-7kJInM1Qo2LJcKyDhuYzh9ZWd+mal/fynfL9BNjWOiTcOpX+jNfqb/UmGUqros5pceBITlWGqS4lU709yHFUbg== + dependencies: + "@resolver-engine/core" "^0.2.1" + debug "^3.1.0" + +"@resolver-engine/imports-fs@^0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@resolver-engine/imports-fs/-/imports-fs-0.2.2.tgz#5a81ef3285dbf0411ab3b15205080a1ad7622d9e" + integrity sha512-gFCgMvCwyppjwq0UzIjde/WI+yDs3oatJhozG9xdjJdewwtd7LiF0T5i9lrHAUtqrQbqoFE4E+ZMRVHWpWHpKQ== + dependencies: + "@resolver-engine/fs" "^0.2.1" + "@resolver-engine/imports" "^0.2.2" + debug "^3.1.0" + +"@resolver-engine/imports@^0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@resolver-engine/imports/-/imports-0.2.2.tgz#d3de55a1bb5f3beb7703fdde743298f321175843" + integrity sha512-u5/HUkvo8q34AA+hnxxqqXGfby5swnH0Myw91o3Sm2TETJlNKXibFGSKBavAH+wvWdBi4Z5gS2Odu0PowgVOUg== + dependencies: + "@resolver-engine/core" "^0.2.1" + debug "^3.1.0" + hosted-git-info "^2.6.0" + +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + +"@types/bn.js@^4.11.4": + version "4.11.5" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.5.tgz#40e36197433f78f807524ec623afcf0169ac81dc" + integrity sha512-AEAZcIZga0JgVMHNtl1CprA/hXX7/wPt79AgR4XqaDt7jyj3QWYw6LPoOiznPtugDmlubUnAahMs2PFxGcQrng== + dependencies: + "@types/node" "*" + +"@types/node@*", "@types/node@^10.3.2": + version "10.12.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" + integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== + +"@types/node@^10.12.18": + version "10.14.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.12.tgz#0eec3155a46e6c4db1f27c3e588a205f767d622f" + integrity sha512-QcAKpaO6nhHLlxWBvpc4WeLrTvPqlHOvaj0s5GriKkA1zq+bsFBPpfYCvQhLqLgYlIko8A9YrPdaMHCo5mBcpg== + +JSONStream@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +abbrev@1.0.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= + +accepts@~1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + integrity sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0= + +agent-base@4, agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + +agent-base@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== + dependencies: + es6-promisify "^5.0.0" + +agentkeepalive@^3.4.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz#a113924dd3fa24a0bc3b78108c450c2abee00f67" + integrity sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ== + dependencies: + humanize-ms "^1.2.1" + +ajv@^5.2.2: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +ajv@^6.5.5: + version "6.6.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.2.tgz#caceccf474bf3fc3ce3b147443711a24063cc30d" + integrity sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= + +ansi-align@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" + integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== + dependencies: + string-width "^3.0.0" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +any-promise@1.3.0, any-promise@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA== + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +app-module-path@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/app-module-path/-/app-module-path-2.2.0.tgz#641aa55dfb7d6a6f0a8141c4b9c0aa50b6c24dd5" + integrity sha1-ZBqlXft9am8KgUHEucCqULbCTdU= + +aproba@^1.0.3, aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= + dependencies: + arr-flatten "^1.0.1" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + integrity sha1-GdOGodntxufByF04iu28xW0zYC0= + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== + +async@1.x: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= + +async@2.6.1, async@^2.5.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== + dependencies: + lodash "^4.17.10" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-js@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978" + integrity sha1-EQHpVE9KdrG8OybUUsqW16NeeXg= + +base64-js@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +bignumber.js@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-8.0.1.tgz#5d419191370fb558c64e3e5f70d68e5947138832" + integrity sha512-zAySveTJXkgLYCBi0b14xzfnOs+f3G6x36I8w2a1+PFQpWk/dp0mI0F+ZZK2bu+3ELewDcSyP+Cfq++NcHX7sg== + +binary-extensions@^1.0.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14" + integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg== + +bindings@^1.2.1, bindings@^1.3.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +bluebird@^3.5.0: + version "3.5.3" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" + integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== + +bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5: + version "3.5.5" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" + integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== + +bn.js@4.11.6: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + integrity sha1-UzRK2xRhehP26N0s4okF0cC6MhU= + +bn.js@4.11.8, bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + +body-parser@1.18.3, body-parser@^1.16.0: + version "1.18.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" + on-finished "~2.3.0" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" + +boxen@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-3.2.0.tgz#fbdff0de93636ab4450886b6ff45b92d098f45eb" + integrity sha512-cU4J/+NodM3IHdSL2yN8bqYqnmlBTidDR4RC7nJs61ZmtGz8VZzM3HLQX0zY5mrSmPtR3xWwsq2jOUQqFZN8+A== + dependencies: + ansi-align "^3.0.0" + camelcase "^5.3.1" + chalk "^2.4.2" + cli-boxes "^2.2.0" + string-width "^3.0.0" + term-size "^1.2.0" + type-fest "^0.3.0" + widest-line "^2.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browser-stdout@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" + integrity sha1-81HTKWnTL6XXpVZxVCY9korjvR8= + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sha3@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/browserify-sha3/-/browserify-sha3-0.0.4.tgz#086c47b8c82316c9d47022c26185954576dd8e26" + integrity sha1-CGxHuMgjFsnUcCLCYYWVRXbdjiY= + dependencies: + js-sha3 "^0.6.1" + safe-buffer "^5.1.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-to-arraybuffer@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" + integrity sha1-YGSkD6dutDxyOrqe+PbhIW0QURo= + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^3.0.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-3.6.0.tgz#a72c936f77b96bf52f5f7e7b467180628551defb" + integrity sha1-pyyTb3e5a/UvX357RnGAYoVR3vs= + dependencies: + base64-js "0.0.8" + ieee754 "^1.1.4" + isarray "^1.0.0" + +buffer@^5.0.5: + version "5.2.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.1.tgz#dd57fa0f109ac59c602479044dca7b8b3d0b71d6" + integrity sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + +builtins@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +cacache@^12.0.0: + version "12.0.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.2.tgz#8db03205e36089a3df6954c66ce92541441ac46c" + integrity sha512-ifKgxH2CKhJEg6tNdAwziu6Q33EvuG26tYcda6PT3WKisZcYDXsnEdnRv67Po3yCzFfaSoMjGZzJyD2c3DT1dg== + dependencies: + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + infer-owner "^1.0.3" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +charenc@~0.0.1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= + +chokidar@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg= + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cint@^8.2.1: + version "8.2.1" + resolved "https://registry.yarnpkg.com/cint/-/cint-8.2.1.tgz#70386b1b48e2773d0d63166a55aff94ef4456a12" + integrity sha1-cDhrG0jidz0NYxZqVa/5TvRFahI= + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cli-boxes@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.0.tgz#538ecae8f9c6ca508e3c3c95b453fe93cb4c168d" + integrity sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w== + +cli-table@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM= + dependencies: + colors "1.0.3" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +colors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= + +colors@^1.1.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" + integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" + integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== + dependencies: + delayed-stream "~1.0.0" + +command-exists@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.8.tgz#715acefdd1223b9c9b37110a149c6392c2852291" + integrity sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw== + +commander@2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== + +commander@2.15.1: + version "2.15.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" + integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== + +commander@^2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + +commander@^2.9.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== + +commander@~2.17.1: + version "2.17.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== + +commander@~2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ= + dependencies: + graceful-readlink ">= 1.0.0" + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +configstore@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-4.0.0.tgz#5933311e95d3687efb592c528b922d9262d227e7" + integrity sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ== + dependencies: + dot-prop "^4.1.0" + graceful-fs "^4.1.2" + make-dir "^1.0.0" + unique-string "^1.0.0" + write-file-atomic "^2.0.0" + xdg-basedir "^3.0.0" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + +cookiejar@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" + integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cors@^2.8.1: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +crypt@~0.0.1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= + +crypto-browserify@3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= + +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +death@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/death/-/death-1.1.0.tgz#01aa9c401edd92750514470b8266390c66c67318" + integrity sha1-AaqcQB7dknUFFEcLgmY5DGbGcxg= + +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +decompress-response@^3.2.0, decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" + integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== + dependencies: + file-type "^5.2.0" + is-stream "^1.1.0" + tar-stream "^1.5.2" + +decompress-tarbz2@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" + integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== + dependencies: + decompress-tar "^4.1.0" + file-type "^6.1.0" + is-stream "^1.1.0" + seek-bzip "^1.0.5" + unbzip2-stream "^1.0.9" + +decompress-targz@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" + integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== + dependencies: + decompress-tar "^4.1.1" + file-type "^5.2.0" + is-stream "^1.1.0" + +decompress-unzip@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" + integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= + dependencies: + file-type "^3.8.0" + get-stream "^2.2.0" + pify "^2.3.0" + yauzl "^2.4.2" + +decompress@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.0.tgz#7aedd85427e5a92dacfe55674a7c505e96d01f9d" + integrity sha1-eu3YVCflqS2s/lVnSnxQXpbQH50= + dependencies: + decompress-tar "^4.0.0" + decompress-tarbz2 "^4.0.0" + decompress-targz "^4.0.0" + decompress-unzip "^4.0.1" + graceful-fs "^4.1.10" + make-dir "^1.0.0" + pify "^2.3.0" + strip-dirs "^2.0.0" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +defer-to-connect@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.0.2.tgz#4bae758a314b034ae33902b5aac25a8dd6a8633e" + integrity sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw== + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-installed@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-installed/-/detect-installed-2.0.4.tgz#a0850465e7c3ebcff979d6b6535ad344b80dd7c5" + integrity sha1-oIUEZefD68/5eda2U1rTRLgN18U= + dependencies: + get-installed-path "^2.0.3" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +diff@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" + integrity sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww== + +diff@3.5.0, diff@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dom-walk@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" + integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg= + +dot-prop@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== + dependencies: + is-obj "^1.0.0" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +elliptic@6.3.3: + version "6.3.3" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.3.tgz#5482d9646d54bcb89fd7d994fc9e2e9568876e3f" + integrity sha1-VILZZG1UvLif19mU/J4ulWiHbj8= + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + inherits "^2.0.1" + +elliptic@^6.0.0, elliptic@^6.4.0: + version "6.4.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" + integrity sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ== + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= + dependencies: + iconv-lite "~0.4.13" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== + dependencies: + once "^1.4.0" + +eol@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/eol/-/eol-0.9.1.tgz#f701912f504074be35c6117a5c4ade49cd547acd" + integrity sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg== + +err-code@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" + integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= + +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escodegen@1.8.x: + version "1.8.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" + integrity sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg= + dependencies: + esprima "^2.7.1" + estraverse "^1.9.1" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.2.0" + +esprima@2.7.x, esprima@^2.7.1: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +estraverse@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" + integrity sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q= + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eth-ens-namehash@2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" + integrity sha1-IprEbsqG1S4MmR58sq74P/D2i88= + dependencies: + idna-uts46-hx "^2.3.1" + js-sha3 "^0.5.7" + +eth-lib@0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.7.tgz#2f93f17b1e23aec3759cd4a3fe20c1286a3fc1ca" + integrity sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco= + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + xhr-request-promise "^0.1.2" + +eth-lib@0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" + integrity sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw== + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + xhr-request-promise "^0.1.2" + +eth-lib@^0.1.26: + version "0.1.27" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.27.tgz#f0b0fd144f865d2d6bf8257a40004f2e75ca1dd6" + integrity sha512-B8czsfkJYzn2UIEMwjc7Mbj+Cy72V+/OXH/tb44LV8jhrjizQJJ325xMOMyk3+ETa6r6oi0jsUY14+om8mQMWA== + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + keccakjs "^0.2.1" + nano-json-stream-parser "^0.1.2" + servify "^0.1.12" + ws "^3.0.0" + xhr-request-promise "^0.1.2" + +ethereumjs-testrpc-sc@6.4.5-sc.3: + version "6.4.5-sc.3" + resolved "https://registry.yarnpkg.com/ethereumjs-testrpc-sc/-/ethereumjs-testrpc-sc-6.4.5-sc.3.tgz#7c02bfb4c07f32d0ccb30140b61736e5f1bb71c4" + integrity sha512-uQD5Tf+C1QgXRx4GkYnlkB6UxLInkbn2gZzwAKLbnDKIzqcv4JiKVUJxnHyYrbXAu0IAxexus7jYnpju2yDHqw== + dependencies: + bn.js "4.11.8" + source-map-support "0.5.9" + yargs "11.1.0" + +ethers@4.0.0-beta.3: + version "4.0.0-beta.3" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.0-beta.3.tgz#15bef14e57e94ecbeb7f9b39dd0a4bd435bc9066" + integrity sha512-YYPogooSknTwvHg3+Mv71gM/3Wcrx+ZpCzarBj3mqs9njjRkrOo2/eufzhHloOCo3JSoNI4TQJJ6yU5ABm3Uog== + dependencies: + "@types/node" "^10.3.2" + aes-js "3.0.0" + bn.js "^4.4.0" + elliptic "6.3.3" + hash.js "1.1.3" + js-sha3 "0.5.7" + scrypt-js "2.0.3" + setimmediate "1.0.4" + uuid "2.0.1" + xmlhttprequest "1.8.0" + +ethers@^4.0.27, ethers@^4.0.32: + version "4.0.33" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.33.tgz#f7b88d2419d731a39aefc37843a3f293e396f918" + integrity sha512-lAHkSPzBe0Vj+JrhmkEHLtUEKEheVktIjGDyE9gbzF4zf1vibjYgB57LraDHu4/ItqWVkztgsm8GWqcDMN+6vQ== + dependencies: + "@types/node" "^10.3.2" + aes-js "3.0.0" + bn.js "^4.4.0" + elliptic "6.3.3" + hash.js "1.1.3" + js-sha3 "0.5.7" + scrypt-js "2.0.4" + setimmediate "1.0.4" + uuid "2.0.1" + xmlhttprequest "1.8.0" + +ethjs-unit@0.1.6, ethjs-unit@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" + integrity sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk= + dependencies: + bn.js "4.11.6" + number-to-bn "1.7.0" + +ethlint@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/ethlint/-/ethlint-1.2.2.tgz#29efb5edd54a44863cbb694da1e4cd269b2fd5f9" + integrity sha512-yzk7XeBuDLPn0iHuC7FUiY4DvXoXFgP4dmIJ1VwnzrXD5L0O9kCpjUMN9PxRbLbxKAm+PbmmVSh4DgPQjhmjeQ== + dependencies: + ajv "^5.2.2" + chokidar "^1.6.0" + colors "^1.1.2" + commander "^2.9.0" + diff "^3.5.0" + eol "^0.9.1" + js-string-escape "^1.0.1" + lodash "^4.14.2" + sol-digger "0.0.2" + sol-explore "1.6.1" + solium-plugin-security "0.1.1" + solparse "2.2.8" + text-table "^0.2.0" + +eventemitter3@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" + integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA== + +eventemitter3@3.1.2, eventemitter3@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" + integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= + dependencies: + is-posix-bracket "^0.1.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= + dependencies: + fill-range "^2.1.0" + +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= + dependencies: + homedir-polyfill "^1.0.1" + +express@^4.14.0: + version "4.16.4" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" + integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.3" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.1" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.4" + qs "6.5.2" + range-parser "~1.2.0" + safe-buffer "5.1.2" + send "0.16.2" + serve-static "1.13.2" + setprototypeof "1.1.0" + statuses "~1.4.0" + type-is "~1.6.16" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= + dependencies: + is-extglob "^1.0.0" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + +fast-diff@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" + +figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== + +file-type@^3.8.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" + integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= + +file-type@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" + integrity sha1-LdvqfHP/42No365J3DOMBYwritY= + +file-type@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" + integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= + +fill-range@^2.1.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^3.0.0" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.4.0" + unpipe "~1.0.0" + +find-up@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +for-each@^0.3.2: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + integrity sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A= + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-extra@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== + dependencies: + minipass "^2.2.1" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +ganache-cli@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/ganache-cli/-/ganache-cli-6.3.0.tgz#574f9d35aaec8da6e01c2be49db8fe73129eb561" + integrity sha512-8SyzfX2ipRVBx1fBZLg3j8I3E334U3Vazk5mEpYcWqnIjC2ace6jtOXHG4aTuAvSz3+HzQ8p8pRjOJxdDZ2pnQ== + dependencies: + bn.js "4.11.8" + source-map-support "0.5.9" + yargs "11.1.0" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +genfun@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" + integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA== + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-installed-path@^2.0.3: + version "2.1.1" + resolved "https://registry.yarnpkg.com/get-installed-path/-/get-installed-path-2.1.1.tgz#a1f33dc6b8af542c9331084e8edbe37fe2634152" + integrity sha512-Qkn9eq6tW5/q9BDVdMpB8tOHljX9OSP0jRC5TRNVA4qRc839t4g8KQaR8t0Uv0EFVL0MlyG7m/ofjEgAROtYsA== + dependencies: + global-modules "1.0.0" + +get-installed-path@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/get-installed-path/-/get-installed-path-4.0.8.tgz#a4fee849f5f327c12c551bb37477acd5151e5f7d" + integrity sha512-PmANK1xElIHlHH2tXfOoTnSDUjX1X3GvKK6ZyLbUnSCCn1pADwu67eVWttuPzJWrXDDT2MfO6uAaKILOFfitmA== + dependencies: + global-modules "1.0.0" + +get-stdin@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6" + integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ== + +get-stream@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" + integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= + dependencies: + object-assign "^4.0.1" + pinkie-promise "^2.0.0" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" + integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= + dependencies: + is-glob "^2.0.0" + +glob@7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^5.0.15: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.0: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.3, glob@^7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" + integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= + dependencies: + ini "^1.3.4" + +global-modules@1.0.0, global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + +global@~4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" + integrity sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8= + dependencies: + min-document "^2.19.0" + process "~0.5.1" + +got@9.6.0, got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + +got@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" + integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== + dependencies: + decompress-response "^3.2.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-plain-obj "^1.1.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + p-cancelable "^0.3.0" + p-timeout "^1.1.1" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + url-parse-lax "^1.0.0" + url-to-options "^1.0.1" + +graceful-fs@^4.1.10, graceful-fs@^4.1.11: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + +graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: + version "4.2.0" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" + integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= + +growl@1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" + integrity sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q== + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +handlebars@^4.0.1: + version "4.0.12" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" + integrity sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA== + dependencies: + async "^2.5.0" + optimist "^0.6.1" + source-map "^0.6.1" + optionalDependencies: + uglify-js "^3.1.4" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= + +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-symbol-support-x@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== + +has-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== + dependencies: + has-symbol-support-x "^1.4.1" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has-yarn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" + integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + integrity sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +he@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== + dependencies: + parse-passwd "^1.0.0" + +hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== + +http-cache-semantics@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + +http-cache-semantics@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz#495704773277eeef6e43f9ab2c2c7d259dda25c5" + integrity sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew== + +http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-https@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" + integrity sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs= + +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== + dependencies: + agent-base "4" + debug "3.1.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-proxy-agent@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz#271ea8e90f836ac9f119daccd39c19ff7dfb0793" + integrity sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg== + dependencies: + agent-base "^4.3.0" + debug "^3.1.0" + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= + dependencies: + ms "^2.0.0" + +iconv-lite@0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.4.4, iconv-lite@~0.4.13: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +idna-uts46-hx@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" + integrity sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA== + dependencies: + punycode "2.1.0" + +ieee754@^1.1.4: + version "1.1.12" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" + integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA== + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== + dependencies: + minimatch "^3.0.4" + +immutable@^4.0.0-rc.12: + version "4.0.0-rc.12" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0-rc.12.tgz#ca59a7e4c19ae8d9bf74a97bdf0f6e2f2a5d0217" + integrity sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A== + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +infer-owner@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +interpret@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + +ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4= + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5, is-buffer@~1.1.1: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-function@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" + integrity sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU= + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= + dependencies: + is-extglob "^1.0.0" + +is-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" + integrity sha1-fY035q135dEnFIkTxXPggtd39VQ= + +is-installed-globally@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" + integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA= + dependencies: + global-dirs "^0.1.0" + is-path-inside "^1.0.0" + +is-natural-number@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" + integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= + +is-npm@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-3.0.0.tgz#ec9147bfb629c43f494cf67936a961edec7e8053" + integrity sha512-wsigDr1Kkschp2opC4G3yA6r9EgVA6NjRpWzIi9axXqeIaAATPRJc4uLujXe3Nd9uO8KoDyA4MD6aZSeXTADhA== + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= + +is-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" + integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= + dependencies: + path-is-inside "^1.0.1" + +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= + +is-retry-allowed@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ= + +is-stream@^1.0.0, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-windows@^1.0.1, is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-yarn-global@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" + integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +istanbul@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" + integrity sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs= + dependencies: + abbrev "1.0.x" + async "1.x" + escodegen "1.8.x" + esprima "2.7.x" + glob "^5.0.15" + handlebars "^4.0.1" + js-yaml "3.x" + mkdirp "0.5.x" + nopt "3.x" + once "1.x" + resolve "1.1.x" + supports-color "^3.1.0" + which "^1.1.1" + wordwrap "^1.0.0" + +isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== + dependencies: + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" + +jju@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" + integrity sha1-o6vicYryQaKykE+EpiWXDzia4yo= + +js-sha3@0.5.7, js-sha3@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" + integrity sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc= + +js-sha3@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.6.1.tgz#5b89f77a7477679877f58c4a075240934b1f95c0" + integrity sha1-W4n3enR3Z5h39YxKB1JAk0sflcA= + +js-string-escape@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" + integrity sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8= + +js-yaml@3.x, js-yaml@^3.12.0: + version "3.12.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600" + integrity sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + +json-parse-better-errors@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-parse-helpfulerror@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz#13f14ce02eed4e981297b64eb9e3b932e2dd13dc" + integrity sha1-E/FM4C7tTpgSl7ZOueO5MuLdE9w= + dependencies: + jju "^1.1.0" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json5@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" + integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== + dependencies: + minimist "^1.2.0" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + integrity sha1-NzaitCi4e72gzIO1P6PWM6NcKug= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +keccak@^1.0.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-1.4.0.tgz#572f8a6dbee8e7b3aa421550f9e6408ca2186f80" + integrity sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw== + dependencies: + bindings "^1.2.1" + inherits "^2.0.3" + nan "^2.2.1" + safe-buffer "^5.1.0" + +keccakjs@^0.2.1: + version "0.2.3" + resolved "https://registry.yarnpkg.com/keccakjs/-/keccakjs-0.2.3.tgz#5e4e969ce39689a3861f445d7752ee3477f9fe72" + integrity sha512-BjLkNDcfaZ6l8HBG9tH0tpmDv3sS2mA7FNQxFHpCdzP3Gb2MVruXBSuoM66SnVxKJpAr5dKGdkHD+bDokt8fTg== + dependencies: + browserify-sha3 "^0.0.4" + sha3 "^1.2.2" + +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + integrity sha1-QIhDO0azsbolnXh4XY6W9zugJDk= + optionalDependencies: + graceful-fs "^4.1.9" + +kleur@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +latest-version@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" + integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== + dependencies: + package-json "^6.3.0" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + dependencies: + invert-kv "^1.0.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +libnpmconfig@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/libnpmconfig/-/libnpmconfig-1.2.1.tgz#c0c2f793a74e67d4825e5039e7a02a0044dfcbc0" + integrity sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA== + dependencies: + figgy-pudding "^3.5.1" + find-up "^3.0.0" + ini "^1.3.5" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash@^4.14.2, lodash@^4.16.4, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.2.0: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + +lodash@^4.17.13: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== + dependencies: + pify "^3.0.0" + +make-fetch-happen@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-5.0.0.tgz#a8e3fe41d3415dd656fe7b8e8172e1fb4458b38d" + integrity sha512-nFr/vpL1Jc60etMVKeaLOqfGjMMb3tAHFVJWxHOFCFS04Zmd7kGlMxo0l1tzfhoQje0/UPnd0X8OeGUiXXnfPA== + dependencies: + agentkeepalive "^3.4.1" + cacache "^12.0.0" + http-cache-semantics "^3.8.1" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.1" + lru-cache "^5.1.1" + mississippi "^3.0.0" + node-fetch-npm "^2.0.2" + promise-retry "^1.1.1" + socks-proxy-agent "^4.0.0" + ssri "^6.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +math-random@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" + integrity sha1-izqsWIuKZuSXXjzepn97sylgH6w= + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +md5@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" + integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk= + dependencies: + charenc "~0.0.1" + crypt "~0.0.1" + is-buffer "~1.1.1" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= + dependencies: + mimic-fn "^1.0.0" + +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +micromatch@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@~1.37.0: + version "1.37.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" + integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== + +mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.18, mime-types@~2.1.19: + version "2.1.21" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" + integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== + dependencies: + mime-db "~1.37.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= + dependencies: + dom-walk "^0.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= + +minipass@^2.2.1, minipass@^2.3.4, minipass@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.1, minizlib@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp-promise@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" + integrity sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE= + dependencies: + mkdirp "*" + +mkdirp@*, mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +mocha-junit-reporter@^1.18.0: + version "1.18.0" + resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.18.0.tgz#9209a3fba30025ae3ae5e6bfe7f9c5bc3c2e8ee2" + integrity sha512-y3XuqKa2+HRYtg0wYyhW/XsLm2Ps+pqf9HaTAt7+MVUAKFJaNAHOrNseTZo9KCxjfIbxUWwckP5qCDDPUmjSWA== + dependencies: + debug "^2.2.0" + md5 "^2.1.0" + mkdirp "~0.5.1" + strip-ansi "^4.0.0" + xml "^1.0.0" + +mocha-multi-reporters@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.1.7.tgz#cc7f3f4d32f478520941d852abb64d9988587d82" + integrity sha1-zH8/TTL0eFIJQdhSq7ZNmYhYfYI= + dependencies: + debug "^3.1.0" + lodash "^4.16.4" + +mocha@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" + integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== + dependencies: + browser-stdout "1.3.1" + commander "2.15.1" + debug "3.1.0" + diff "3.5.0" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.5" + he "1.1.1" + minimatch "3.0.4" + mkdirp "0.5.1" + supports-color "5.4.0" + +mocha@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794" + integrity sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA== + dependencies: + browser-stdout "1.3.0" + commander "2.11.0" + debug "3.1.0" + diff "3.3.1" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.3" + he "1.1.1" + mkdirp "0.5.1" + supports-color "4.4.0" + +mock-fs@^4.1.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.7.0.tgz#9f17e219cacb8094f4010e0a8c38589e2b33c299" + integrity sha512-WlQNtUlzMRpvLHf8dqeUmNqfdPjGY29KrJF50Ldb4AcL+vQeR8QH3wQcFMgrhTwb1gHjZn9xggho+84tBskLgA== + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +nan@2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA== + +nan@^2.0.8, nan@^2.3.3, nan@^2.9.2: + version "2.12.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" + integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== + +nan@^2.11.0: + version "2.13.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7" + integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw== + +nan@^2.2.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +nano-json-stream-parser@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" + integrity sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18= + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" + integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA== + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= + +nested-error-stacks@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.0.1.tgz#d2cc9fc5235ddb371fc44d506234339c8e4b0a4b" + integrity sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A== + +node-alias@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/node-alias/-/node-alias-1.0.4.tgz#1f1b916b56b9ea241c0135f97ced6940f556f292" + integrity sha1-HxuRa1a56iQcATX5fO1pQPVW8pI= + dependencies: + chalk "^1.1.1" + lodash "^4.2.0" + +node-fetch-npm@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7" + integrity sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw== + dependencies: + encoding "^0.1.11" + json-parse-better-errors "^1.0.0" + safe-buffer "^5.1.1" + +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +nopt@3.x: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + dependencies: + abbrev "1" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.4.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.0, normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-url@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.3.0.tgz#9c49e10fc1876aeb76dba88bf1b2b5d9fa57b2ee" + integrity sha512-0NLtR71o4k6GLP+mr6Ty34c5GA6CMoEsncKJxvQd8NzPxaHRJNnb5gZE8R1XF4CPIS7QPHLJ74IFszwtNVAHVQ== + +npm-bundled@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" + integrity sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g== + +npm-check-updates@^3.1.11: + version "3.1.20" + resolved "https://registry.yarnpkg.com/npm-check-updates/-/npm-check-updates-3.1.20.tgz#9dd719bc04af9c273b33b44a7d5368d5e85ae9c2" + integrity sha512-mc9BAoOYSTwP/IvoA+ofdkWSipwRvhgC0qop1PvlMZojgzi7N/dykdxOIWrw0OlZPnEKvXkKFEuPk97LrvXE1A== + dependencies: + chalk "^2.4.2" + cint "^8.2.1" + cli-table "^0.3.1" + commander "^2.20.0" + fast-diff "^1.2.0" + find-up "4.1.0" + get-stdin "^7.0.0" + json-parse-helpfulerror "^1.0.3" + libnpmconfig "^1.2.1" + lodash "^4.17.13" + node-alias "^1.0.4" + pacote "^9.5.1" + progress "^2.0.3" + prompts "^2.1.0" + rc-config-loader "^2.0.4" + requireg "^0.2.2" + semver "^6.2.0" + semver-utils "^1.1.4" + spawn-please "^0.3.0" + update-notifier "^3.0.1" + +npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" + integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA== + dependencies: + hosted-git-info "^2.6.0" + osenv "^0.1.5" + semver "^5.5.0" + validate-npm-package-name "^3.0.0" + +npm-packlist@^1.1.12: + version "1.4.4" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44" + integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-packlist@^1.1.6: + version "1.2.0" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.2.0.tgz#55a60e793e272f00862c7089274439a4cc31fc7f" + integrity sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-pick-manifest@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz#32111d2a9562638bb2c8f2bf27f7f3092c8fae40" + integrity sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA== + dependencies: + figgy-pudding "^3.5.1" + npm-package-arg "^6.0.0" + semver "^5.4.1" + +npm-registry-fetch@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-4.0.0.tgz#5ef75845b605855c7964472542c25da172af8677" + integrity sha512-Jllq35Jag8dtv0M17ue74XtdQTyqKzuAYGiX9mAjOhkmNjib3bBUgK6mUY61+AHnXeSRobQkpY3/xIOS/omptw== + dependencies: + JSONStream "^1.3.4" + bluebird "^3.5.1" + figgy-pudding "^3.4.1" + lru-cache "^5.1.1" + make-fetch-happen "^5.0.0" + npm-package-arg "^6.1.0" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +number-to-bn@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" + integrity sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA= + dependencies: + bn.js "4.11.6" + strip-hex-prefix "1.0.0" + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-keys@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" + integrity sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +oboe@2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.4.tgz#20c88cdb0c15371bb04119257d4fdd34b0aa49f6" + integrity sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY= + dependencies: + http-https "^1.0.0" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +original-require@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/original-require/-/original-require-1.0.1.tgz#0f130471584cd33511c5ec38c8d59213f9ac5e20" + integrity sha1-DxMEcVhM0zURxew4yNWSE/msXiA= + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@^0.1.4, osenv@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== + +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" + integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== + dependencies: + p-try "^2.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-timeout@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" + integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= + dependencies: + p-finally "^1.0.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json@^6.3.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" + integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== + dependencies: + got "^9.6.0" + registry-auth-token "^4.0.0" + registry-url "^5.0.0" + semver "^6.2.0" + +pacote@^9.5.1: + version "9.5.4" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.5.4.tgz#8baa26f3d1326d13dc2fe0fe84040a364ae30aad" + integrity sha512-nWr0ari6E+apbdoN0hToTKZElO5h4y8DGFa2pyNA5GQIdcP0imC96bA0bbPw1gpeguVIiUgHHaAlq/6xfPp8Qw== + dependencies: + bluebird "^3.5.3" + cacache "^12.0.0" + figgy-pudding "^3.5.1" + get-stream "^4.1.0" + glob "^7.1.3" + lru-cache "^5.1.1" + make-fetch-happen "^5.0.0" + minimatch "^3.0.4" + minipass "^2.3.5" + mississippi "^3.0.0" + mkdirp "^0.5.1" + normalize-package-data "^2.4.0" + npm-package-arg "^6.1.0" + npm-packlist "^1.1.12" + npm-pick-manifest "^2.2.3" + npm-registry-fetch "^4.0.0" + osenv "^0.1.5" + promise-inflight "^1.0.1" + promise-retry "^1.1.1" + protoduck "^5.0.1" + rimraf "^2.6.2" + safe-buffer "^5.1.2" + semver "^5.6.0" + ssri "^6.0.1" + tar "^4.4.8" + unique-filename "^1.1.1" + which "^1.3.1" + +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY= + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parse-asn1@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" + integrity sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw== + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-headers@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.1.tgz#6ae83a7aa25a9d9b700acc28698cd1f1ed7e9536" + integrity sha1-aug6eqJanZtwCswoaYzR8e1+lTY= + dependencies: + for-each "^0.3.2" + trim "0.0.1" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= + +parseurl@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.5, path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +pbkdf2@^3.0.3: + version "3.0.17" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +pegjs@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/pegjs/-/pegjs-0.10.0.tgz#cf8bafae6eddff4b5a7efb185269eaaf4610ddbd" + integrity sha1-z4uvrm7d/0tafvsYUmnqr0YQ3b0= + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + +process@~0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" + integrity sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8= + +progress@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +promise-retry@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" + integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0= + dependencies: + err-code "^1.0.0" + retry "^0.10.0" + +prompts@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.1.0.tgz#bf90bc71f6065d255ea2bdc0fe6520485c1b45db" + integrity sha512-+x5TozgqYdOwWsQFZizE/Tra3fKvAoy037kOyU6cgz84n8f6zxngLOV4O32kTwt9FcLCxAqw0P/c8rOr9y+Gfg== + dependencies: + kleur "^3.0.2" + sisteransi "^1.0.0" + +protoduck@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.1.tgz#03c3659ca18007b69a50fd82a7ebcc516261151f" + integrity sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg== + dependencies: + genfun "^5.0.0" + +proxy-addr@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.8.0" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.24: + version "1.1.31" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" + integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + integrity sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0= + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@6.5.2, qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystringify@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" + integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== + +randomatic@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" + integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== + dependencies: + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + integrity sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +randomhex@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/randomhex/-/randomhex-0.1.5.tgz#baceef982329091400f2a2912c6cd02f1094f585" + integrity sha1-us7vmCMpCRQA8qKRLGzQLxCU9YU= + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== + dependencies: + bytes "3.0.0" + http-errors "1.6.3" + iconv-lite "0.4.23" + unpipe "1.0.0" + +rc-config-loader@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/rc-config-loader/-/rc-config-loader-2.0.4.tgz#fe23e26a87e2ec07541b29e7f37bfd75807a4c36" + integrity sha512-k06UzRbYDWgF4Mc/YrsZsmzSpDLuHoThJxep+vq5H09hiX8rbA5Ue/Ra0dwWm5MQvWYW4YBXgA186inNxuxidQ== + dependencies: + debug "^4.1.1" + js-yaml "^3.12.0" + json5 "^2.1.0" + object-assign "^4.1.0" + object-keys "^1.0.12" + path-exists "^3.0.0" + require-from-string "^2.0.2" + +rc@^1.2.7, rc@^1.2.8, rc@~1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + +regenerator-runtime@^0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" + integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA== + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== + dependencies: + is-equal-shallow "^0.1.3" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +registry-auth-token@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.0.0.tgz#30e55961eec77379da551ea5c4cf43cbf03522be" + integrity sha512-lpQkHxd9UL6tb3k/aHAVfnVtn+Bcs9ob5InuFLLEDqSqeq+AljB8GZW9xY0x7F+xYwEcjKe07nyoxzEYz6yvkw== + dependencies: + rc "^1.2.8" + safe-buffer "^5.0.1" + +registry-url@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" + integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== + dependencies: + rc "^1.2.8" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +req-cwd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/req-cwd/-/req-cwd-1.0.1.tgz#0d73aeae9266e697a78f7976019677e76acf0fff" + integrity sha1-DXOurpJm5penj3l2AZZ352rPD/8= + dependencies: + req-from "^1.0.1" + +req-from@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/req-from/-/req-from-1.0.1.tgz#bf81da5147947d32d13b947dc12a58ad4587350e" + integrity sha1-v4HaUUeUfTLRO5R9wSpYrUWHNQ4= + dependencies: + resolve-from "^2.0.0" + +request@^2.79.0, request@^2.85.0, request@^2.88.0: + version "2.88.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.0" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.4.3" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-from-string@^2.0.0, require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +requireg@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/requireg/-/requireg-0.2.2.tgz#437e77a5316a54c9bcdbbf5d1f755fe093089830" + integrity sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg== + dependencies: + nested-error-stacks "~2.0.1" + rc "~1.2.7" + resolve "~1.7.1" + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-dir@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@1.1.x: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= + +resolve@^1.1.6: + version "1.9.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06" + integrity sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ== + dependencies: + path-parse "^1.0.6" + +resolve@^1.10.0: + version "1.11.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" + integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== + dependencies: + path-parse "^1.0.6" + +resolve@~1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3" + integrity sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw== + dependencies: + path-parse "^1.0.5" + +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +retry@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= + +rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +rxjs@^6.4.0: + version "6.5.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7" + integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg== + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +scrypt-js@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.3.tgz#bb0040be03043da9a012a2cea9fc9f852cfc87d4" + integrity sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q= + +scrypt-js@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.4.tgz#32f8c5149f0797672e551c07e230f834b6af5f16" + integrity sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw== + +scrypt.js@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/scrypt.js/-/scrypt.js-0.2.0.tgz#af8d1465b71e9990110bedfc593b9479e03a8ada" + integrity sha1-r40UZbcemZARC+38WTuUeeA6ito= + dependencies: + scrypt "^6.0.2" + scryptsy "^1.2.1" + +scrypt.js@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/scrypt.js/-/scrypt.js-0.3.0.tgz#6c62d61728ad533c8c376a2e5e3e86d41a95c4c0" + integrity sha512-42LTc1nyFsyv/o0gcHtDztrn+aqpkaCNt5Qh7ATBZfhEZU7IC/0oT/qbBH+uRNoAPvs2fwiOId68FDEoSRA8/A== + dependencies: + scryptsy "^1.2.1" + optionalDependencies: + scrypt "^6.0.2" + +scrypt@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/scrypt/-/scrypt-6.0.3.tgz#04e014a5682b53fa50c2d5cce167d719c06d870d" + integrity sha1-BOAUpWgrU/pQwtXM4WfXGcBthw0= + dependencies: + nan "^2.0.8" + +scryptsy@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" + integrity sha1-oyJfpLJST4AnAHYeKFW987LZIWM= + dependencies: + pbkdf2 "^3.0.3" + +seek-bzip@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc" + integrity sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w= + dependencies: + commander "~2.8.1" + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY= + dependencies: + semver "^5.0.3" + +semver-utils@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/semver-utils/-/semver-utils-1.1.4.tgz#cf0405e669a57488913909fc1c3f29bf2a4871e2" + integrity sha512-EjnoLE5OGmDAVV/8YDoN5KiajNadjzIp9BAHOhYeQHt7j0UWxjmgsx4YD48wp4Ue1Qogq38F1GNUJNqF1kKKxA== + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + +semver@^5.0.3, semver@^5.4.1, semver@^5.5.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" + integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== + +semver@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +servify@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" + integrity sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw== + dependencies: + body-parser "^1.16.0" + cors "^2.8.1" + express "^4.14.0" + request "^2.79.0" + xhr "^2.3.3" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f" + integrity sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48= + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +sha3@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/sha3/-/sha3-1.2.2.tgz#a66c5098de4c25bc88336ec8b4817d005bca7ba9" + integrity sha1-pmxQmN5MJbyIM27ItIF9AFvKe6k= + dependencies: + nan "2.10.0" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shelljs@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" + integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +simple-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" + integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY= + +simple-get@^2.7.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" + integrity sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw== + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + +sisteransi@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.2.tgz#ec57d64b6f25c4f26c0e2c7dd23f2d7f12f7e418" + integrity sha512-ZcYcZcT69nSLAR2oLN2JwNmLkJEKGooFMCdvOkFrToUt/WfcRWqhIg4P4KwY4dmLbuyXIx4o4YmPsvMRJYJd/w== + +smart-buffer@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.2.tgz#5207858c3815cc69110703c6b94e46c15634395d" + integrity sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw== + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +socks-proxy-agent@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz#3c8991f3145b2799e70e11bd5fbc8b1963116386" + integrity sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg== + dependencies: + agent-base "~4.2.1" + socks "~2.3.2" + +socks@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.3.2.tgz#ade388e9e6d87fdb11649c15746c578922a5883e" + integrity sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ== + dependencies: + ip "^1.1.5" + smart-buffer "4.0.2" + +sol-digger@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/sol-digger/-/sol-digger-0.0.2.tgz#406c4a9d31e269e7f88eb1c2ea101318e5e09025" + integrity sha1-QGxKnTHiaef4jrHC6hATGOXgkCU= + +sol-explore@1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/sol-explore/-/sol-explore-1.6.1.tgz#b59f073c69fe332560d5a10c32ba8ca7f2986cfb" + integrity sha1-tZ8HPGn+MyVg1aEMMrqMp/KYbPs= + +sol-explore@^1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/sol-explore/-/sol-explore-1.6.2.tgz#43ae8c419fd3ac056a05f8a9d1fb1022cd41ecc2" + integrity sha1-Q66MQZ/TrAVqBfip0fsQIs1B7MI= + +solc@0.5.8: + version "0.5.8" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.5.8.tgz#a0aa2714082fc406926f5cb384376d7408080611" + integrity sha512-RQ2SlwPBOBSV7ktNQJkvbiQks3t+3V9dsqD014EdstxnJzSxBuOvbt3P5QXpNPYW1DsEmF7dhOaT3JL7yEae/A== + dependencies: + command-exists "^1.2.8" + fs-extra "^0.30.0" + keccak "^1.0.2" + memorystream "^0.3.1" + require-from-string "^2.0.0" + semver "^5.5.0" + tmp "0.0.33" + yargs "^11.0.0" + +solidity-coverage@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.6.3.tgz#c7e7afa0792ae1fe3c6039735e2a0ad5cb2f0aca" + integrity sha512-mHc8xtcVZwkANAWQrOROyD7eAEE8L5kUE/3KEvNp/y7+zR1/u2f8ouNKp5hKeCAmHhm7df7X3pLGINmnKili9w== + dependencies: + death "^1.1.0" + ethereumjs-testrpc-sc "6.4.5-sc.3" + istanbul "^0.4.5" + keccakjs "^0.2.1" + req-cwd "^1.0.1" + shelljs "^0.8.3" + sol-explore "^1.6.2" + solidity-parser-antlr "^0.4.7" + tree-kill "^1.2.0" + web3 "1.0.0-beta.50" + web3-eth-abi "1.0.0-beta.50" + +solidity-parser-antlr@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/solidity-parser-antlr/-/solidity-parser-antlr-0.4.2.tgz#b862eba5936e7a90b4f5f1c8eb1d33fe86650f78" + integrity sha512-0OKT2YKZAqPe14HN7Nbo24hjmnyUYh92UjyZG0Zz2rpQhl/w8asX8qHb+ASSXfayQaiW8g9zGIupXEE355tOQQ== + +solidity-parser-antlr@^0.4.7: + version "0.4.7" + resolved "https://registry.yarnpkg.com/solidity-parser-antlr/-/solidity-parser-antlr-0.4.7.tgz#8e18867c95a956958ed008371e43f9e571dee6af" + integrity sha512-iVjNhgqkXw+o+0E+xoLcji+3KuXLe8Rm8omUuVGhsV14+ZsTwQ70nhBRXg8O3t9xwdS0iST1q9NJ5IqHnqpWkA== + dependencies: + npm-check-updates "^3.1.11" + +solium-plugin-security@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/solium-plugin-security/-/solium-plugin-security-0.1.1.tgz#2a87bcf8f8c3abf7d198e292e4ac080284e3f3f6" + integrity sha512-kpLirBwIq4mhxk0Y/nn5cQ6qdJTI+U1LO3gpoNIcqNaW+sI058moXBe2UiHs+9wvF9IzYD49jcKhFTxcR9u9SQ== + +solparse@2.2.8, solparse@^2.2.8: + version "2.2.8" + resolved "https://registry.yarnpkg.com/solparse/-/solparse-2.2.8.tgz#d13e42dbed95ce32f43894f5ec53f00d14cf9f11" + integrity sha512-Tm6hdfG72DOxD40SD+T5ddbekWglNWjzDRSNq7ZDIOHVsyaJSeeunUuWNj4DE7uDrJK3tGQuX0ZTDZWNYsGPMA== + dependencies: + mocha "^4.0.1" + pegjs "^0.10.0" + yargs "^10.0.3" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@0.5.9: + version "0.5.9" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" + integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" + integrity sha1-2rc/vPwrqBm03gO9b26qSBZLP50= + dependencies: + amdefine ">=0.0.4" + +spawn-please@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/spawn-please/-/spawn-please-0.3.0.tgz#db338ec4cff63abc69f1d0e08cee9eb8bebd9d11" + integrity sha1-2zOOxM/2Orxp8dDgjO6euL69nRE= + +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz#81c0ce8f21474756148bbb5f3bfc0f36bf15d76e" + integrity sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sshpk@^1.7.0: + version "1.16.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.0.tgz#1d4963a2fbffe58050aa9084ca20be81741c07de" + integrity sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssri@^6.0.0, ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== + dependencies: + figgy-pudding "^3.5.1" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-dirs@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" + integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== + dependencies: + is-natural-number "^4.0.1" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" + integrity sha1-DF8VX+8RUTczd96du1iNoFUA428= + dependencies: + is-hex-prefixed "1.0.0" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +supports-color@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" + integrity sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ== + dependencies: + has-flag "^2.0.0" + +supports-color@5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== + dependencies: + has-flag "^3.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^3.1.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= + dependencies: + has-flag "^1.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +swarm-js@0.1.39, swarm-js@^0.1.39: + version "0.1.39" + resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.39.tgz#79becb07f291d4b2a178c50fee7aa6e10342c0e8" + integrity sha512-QLMqL2rzF6n5s50BptyD6Oi0R1aWlJC5Y17SRIVXRj6OR1DRIPM7nepvrxxkjA1zNzFz6mUOMjfeqeDaWB7OOg== + dependencies: + bluebird "^3.5.0" + buffer "^5.0.5" + decompress "^4.0.0" + eth-lib "^0.1.26" + fs-extra "^4.0.2" + got "^7.1.0" + mime-types "^2.1.16" + mkdirp-promise "^5.0.1" + mock-fs "^4.1.0" + setimmediate "^1.0.5" + tar "^4.0.2" + xhr-request-promise "^0.1.2" + +tar-stream@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + +tar@^4: + version "4.4.8" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" + integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.4" + minizlib "^1.1.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +tar@^4.0.2, tar@^4.4.8: + version "4.4.10" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" + integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.5" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + +term-size@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" + integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk= + dependencies: + execa "^0.7.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +"through@>=2.2.7 <3", through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +timed-out@^4.0.0, timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= + +tmp@0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +tough-cookie@~2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== + dependencies: + psl "^1.1.24" + punycode "^1.4.1" + +tree-kill@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a" + integrity sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q== + +trim@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" + integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= + +truffle-config@^1.1.17: + version "1.1.17" + resolved "https://registry.yarnpkg.com/truffle-config/-/truffle-config-1.1.17.tgz#5f411f453c34809f99373c6ef223608d6f3f4d6e" + integrity sha512-XayW+x0o3HrPY74UXkmD1kMhyRftXUzBb2UEE5aUnlLr4HEsY4OoJPoMecgwLoOqC3kRJNNXhHtJqJv6w9S1RA== + dependencies: + configstore "^4.0.0" + find-up "^2.1.0" + lodash "^4.17.13" + original-require "1.0.1" + truffle-error "^0.0.5" + truffle-provider "^0.1.13" + +truffle-error@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/truffle-error/-/truffle-error-0.0.5.tgz#6b5740c9f3aac74f47b85d654fff7fe2c1fc5e0e" + integrity sha512-JpzPLMPSCE0vaZ3vH5NO5u42GpMj/Y1SRBkQ6b69PSw3xMSH1umApN32cEcg1nnh8q5FNYc5FnKu0m4tiBffyQ== + +truffle-expect@^0.0.9: + version "0.0.9" + resolved "https://registry.yarnpkg.com/truffle-expect/-/truffle-expect-0.0.9.tgz#d4f0e4aae06333c7c1e093c8f6c0355eb7f9b0c3" + integrity sha512-8ifOoAiRVHsmM8vsn4xATsa4zifTsRA3vt7rsz1ryP2JE+uUqavqQficdh2uVJoa/DIid6O7iZ7J1HtQsHikOQ== + +truffle-flattener@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/truffle-flattener/-/truffle-flattener-1.3.0.tgz#a5b0340897e32cf8389fea105b52fa93c335f04c" + integrity sha512-ppJ9xI0tDuvCYjQlcWwMBcOKZph5U4YpG/gChyUVDxOjUIniG5g7y9vZho2PRj1FohPPnOjg1KOAVNlk/bPZrw== + dependencies: + "@resolver-engine/imports-fs" "^0.2.2" + find-up "^2.1.0" + mkdirp "^0.5.1" + solidity-parser-antlr "^0.4.0" + tsort "0.0.1" + +truffle-hdwallet-provider@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/truffle-hdwallet-provider/-/truffle-hdwallet-provider-1.0.5.tgz#76059fb37d13df70bf37a9c296cf27d5a944e112" + integrity sha512-T9qNm7b6MD0UPWVmmJEhgzW1DdR6mkMDijGBSbdJqYaaBLufoycE+qH3dsV+m1mLTE+ebM5RcJ4gF4oXgDW67w== + dependencies: + any-promise "^1.3.0" + bindings "^1.3.1" + websocket "^1.0.28" + +truffle-interface-adapter@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/truffle-interface-adapter/-/truffle-interface-adapter-0.2.2.tgz#f2ca897b4769b2190e3fb03f09fb98a178362126" + integrity sha512-dAKN+mSOlQV/+PlzUhBH90RAWrbp0Avm8nQcALoTwKa35PkS5RyB2ir1Y0AVoZvKVFYOmRDt884KHpZe8YgJRA== + dependencies: + bn.js "^4.11.8" + ethers "^4.0.32" + lodash "^4.17.13" + web3 "^1.2.0" + +truffle-provider@^0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/truffle-provider/-/truffle-provider-0.1.13.tgz#e121dc190101e57db238b9283f8b1066a468bf15" + integrity sha512-zbO8fNLCHfcDyaC2MI+l5eybN2aUGBpVoQcEHGov2U5LD2F6GJP8Vb3gf/Eqb//X3kZSKaUfGmy32hc87qxvBA== + dependencies: + truffle-error "^0.0.5" + truffle-interface-adapter "^0.2.2" + web3 "^1.2.0" + +truffle-provisioner@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/truffle-provisioner/-/truffle-provisioner-0.1.5.tgz#f940b2e0aa3a26d5227dfc4ebe8d29ebc68a9e03" + integrity sha512-XSzD4Tj1T16E8qwoIHnQ9sOuvoemP1yqxX9Jg0VvvoLTdl8X17uau6dN08JgNR09hJroTrXPbkAi5Y8IfKhVMw== + +truffle-resolver@^5.0.0: + version "5.0.14" + resolved "https://registry.yarnpkg.com/truffle-resolver/-/truffle-resolver-5.0.14.tgz#f403f944bb77a02ca8c2da86dc27a82145641ba4" + integrity sha512-00Uhhm4PchDobtbgjr0e8j4LBAQoZuuS9guKTx3YGHYp10992KVJTsQ+7lZf0K4fGTA2OV/ON0BsN7Sj/xij/Q== + dependencies: + async "2.6.1" + detect-installed "^2.0.4" + get-installed-path "^4.0.8" + truffle-expect "^0.0.9" + truffle-provisioner "^0.1.5" + +truffle@^5.0.30: + version "5.0.30" + resolved "https://registry.yarnpkg.com/truffle/-/truffle-5.0.30.tgz#13ac335939fc6c908c615c25cd94c7a56ba674d5" + integrity sha512-l13cUq5QUEPfW89b4dDBIahNmDWazpey4Y8UJXhNn+YTkHxVM5h8L8eNNIBTD1SiYerrXfw49QMIQubEcz3erA== + dependencies: + app-module-path "^2.2.0" + mocha "5.2.0" + original-require "1.0.1" + +tslib@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== + +tsort@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" + integrity sha1-4igPXoF/i/QnVlf9D5rr1E9aJ4Y= + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-fest@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" + integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== + +type-is@~1.6.16: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +typedarray-to-buffer@^3.1.2, typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +uglify-js@^3.1.4: + version "3.4.9" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" + integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q== + dependencies: + commander "~2.17.1" + source-map "~0.6.1" + +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== + +unbzip2-stream@^1.0.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz#7854da51622a7e63624221196357803b552966a1" + integrity sha512-fIZnvdjblYs7Cru/xC6tCPVhz7JkYcVQQkePwMLyQELzYTds2Xn8QefPVnvdVhhZqubxNA1cASXEH5wcK0Bucw== + dependencies: + buffer "^3.0.1" + through "^2.3.6" + +underscore@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" + integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo= + dependencies: + crypto-random-string "^1.0.0" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +update-notifier@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-3.0.1.tgz#78ecb68b915e2fd1be9f767f6e298ce87b736250" + integrity sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ== + dependencies: + boxen "^3.0.0" + chalk "^2.0.1" + configstore "^4.0.0" + has-yarn "^2.1.0" + import-lazy "^2.1.0" + is-ci "^2.0.0" + is-installed-globally "^0.1.0" + is-npm "^3.0.0" + is-yarn-global "^0.3.0" + latest-version "^5.0.0" + semver-diff "^2.0.0" + xdg-basedir "^3.0.0" + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= + dependencies: + prepend-http "^1.0.1" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + +url-parse@1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.4.tgz#cac1556e95faa0303691fec5cf9d5a1bc34648f8" + integrity sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg== + dependencies: + querystringify "^2.0.0" + requires-port "^1.0.0" + +url-set-query@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" + integrity sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk= + +url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +utf8@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.1.tgz#2e01db02f7d8d0944f77104f1609eb0c304cf768" + integrity sha1-LgHbAvfY0JRPdxBPFgnrDDBM92g= + +utf8@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" + integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac" + integrity sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w= + +uuid@3.3.2, uuid@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +validate-npm-package-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= + dependencies: + builtins "^1.0.3" + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +web3-bzz@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.0.0-beta.50.tgz#5e234eecf427b33f773c78c00e34d370b542f6b0" + integrity sha512-0jD4/g+apH7t87cA9gXoZpvvVW7OqQtbu+X+olFKPrS9pKbkwfaKPdRwc1BNbjqvrRYN0K7koT9xV+Lzvyah6w== + dependencies: + "@babel/runtime" "^7.3.1" + "@types/node" "^10.12.18" + lodash "^4.17.11" + swarm-js "^0.1.39" + +web3-bzz@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.0.tgz#eab70a2cf6c437223f40fc069499fe70ff53feb0" + integrity sha512-QEIdvguSEpqBK9b815nzx4yvpfKv/SAvaFeCMjQ0vjIVqFhAwBHDxd+f+X3nWGVRGVeOTP7864tau26CPBtQ8Q== + dependencies: + got "9.6.0" + swarm-js "0.1.39" + underscore "1.9.1" + +web3-core-helpers@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.50.tgz#0de88656ffa5f13659141cc443ff8529f109deac" + integrity sha512-B1LMrlC9c5HEJYmBWUhsxHdJ78w5YGop/ptF1cFL8cHLwTCQqCFFKLgYUg+dax/554TP1xgJ2w/ArLpnPJ8dBg== + dependencies: + "@babel/runtime" "^7.3.1" + lodash "^4.17.11" + web3-eth-iban "1.0.0-beta.50" + web3-utils "1.0.0-beta.50" + +web3-core-helpers@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.0.tgz#023947323cebd021e43a67145a5087627ce87fb3" + integrity sha512-KLCCP2FS1cMz23Y9l3ZaEDzaUky+GpsNavl4Hn1xX8lNaKcfgGEF+DgtAY/TfPQYAxLjLrSbIFUDzo9H/W1WAQ== + dependencies: + underscore "1.9.1" + web3-eth-iban "1.2.0" + web3-utils "1.2.0" + +web3-core-method@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.0.0-beta.50.tgz#4f9b55699f6e46f49dc8ac6bde204f9ae877b513" + integrity sha512-0+L37KDT90DD1fcTye/ZWMyGOLiw0ZxX2vaC8qDSFvAV3scTEuZyEQuR+tCM2aGyUVihy8LdmZwioRwnTXgLwg== + dependencies: + "@babel/runtime" "^7.3.1" + eventemitter3 "3.1.0" + lodash "^4.17.11" + +web3-core-method@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.0.tgz#9f6a6939d15f53bc74d086f280fbd62461546cd3" + integrity sha512-Iff5rCL+sgHe6zZVZijp818aRixKQf3ZAyQsT6ewER1r9yqXsH89DJtX33Xw8xiaYSwUFcpNs2j+Kluhv/eVAw== + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.0" + web3-core-promievent "1.2.0" + web3-core-subscriptions "1.2.0" + web3-utils "1.2.0" + +web3-core-promievent@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.0.tgz#d6454837a307da5b453fe3077743fe25801a07a1" + integrity sha512-9THNYsZka91AX4LZGZvka5hio9+QlOY22hNgCiagmCmYytyKk3cXftL6CWefnNF7XgW8sy/ew5lzWLVsQW61Lw== + dependencies: + any-promise "1.3.0" + eventemitter3 "3.1.2" + +web3-core-requestmanager@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.0.tgz#a7f9995495340037e7ac72792c1885c35c1e7616" + integrity sha512-hPe1jyESodXAiE7qJglu7ySo4GINCn5CgG+9G1ATLQbriZsir83QMSeKQekv/hckKFIf4SvZJRPEBhtAle+Dhw== + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.0" + web3-providers-http "1.2.0" + web3-providers-ipc "1.2.0" + web3-providers-ws "1.2.0" + +web3-core-subscriptions@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.50.tgz#73df7143062f915e02b153239af10974e350e20f" + integrity sha512-q2Jmuy/BCwcKCFjR6kc03hPbdC6sR0n3IhPVg98Sk7ewgRLur/v3lLDz0fQpY4xE6U0XOqrjxwzlqISkOcP5Kw== + dependencies: + "@babel/runtime" "^7.3.1" + eventemitter3 "^3.1.0" + lodash "^4.17.11" + +web3-core-subscriptions@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.0.tgz#d359b9b5fb6f6a700f1b383be11de7925cb7549f" + integrity sha512-DHipGH8It5E4HxxvymhkudcYhBVgGx6MwGWobIVKFgp6JRxtuvAbqwrMbuD/+78J6yXOa4y9zVXBk12dm2NXGg== + dependencies: + eventemitter3 "3.1.2" + underscore "1.9.1" + web3-core-helpers "1.2.0" + +web3-core@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.0.0-beta.50.tgz#385137b8c34257db2679e925dfe41b98a0f7fe37" + integrity sha512-edOHdSnkRREi0vUXXNUsrbkTvXftCDroiF2tEvbPVyiBv0U6/VDYClFdHuZKdrrTRUcn/rUbvBqw8qCt3xgcuQ== + dependencies: + "@babel/runtime" "^7.3.1" + "@types/node" "^10.12.18" + lodash "^4.17.11" + web3-utils "1.0.0-beta.50" + +web3-core@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.0.tgz#6f3c59f84b2af9ab0ee7617d3c5208a814d3953c" + integrity sha512-Vy+fargzx94COdihE79zIM5lb/XAl/LJlgGdmz2a6QhgGZrSL8K6DKKNS+OuORAcLJN2PWNMc4IdfknkOw1PhQ== + dependencies: + web3-core-helpers "1.2.0" + web3-core-method "1.2.0" + web3-core-requestmanager "1.2.0" + web3-utils "1.2.0" + +web3-eth-abi@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.50.tgz#52ca509257648c6088aa9d8874d6ea5f249c6de7" + integrity sha512-Nwm1HL3xBbrs43j/9V3gH1CJWWR7jyTDSE7PIkjYVjwgygAjlHPMHzuzGffoFMp2tSQ2DywCGmXAY5I5+vznZw== + dependencies: + "@babel/runtime" "^7.3.1" + ethers "^4.0.27" + lodash "^4.17.11" + web3-utils "1.0.0-beta.50" + +web3-eth-abi@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.0.tgz#26b22261756ffbb3363bc37c1a6f5143bebb6469" + integrity sha512-FDuPq/tFeMg/D/f7cNSmvVYkMYb1z379gUUzSL8ZFtZrdHPkezq+lq/TmWmbCOMLYNXlhGJBzjGdLXRS4Upprg== + dependencies: + ethers "4.0.0-beta.3" + underscore "1.9.1" + web3-utils "1.2.0" + +web3-eth-accounts@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.50.tgz#e405979db8d4dc0caccff576fa746cea3d87e3d1" + integrity sha512-cUuYxKhymob87zCUYgw7ieZY6aVStMhClocblI3FKNdI1I8dczhdhZ97qMj5iavOganN7/OxLzeji7ksAoNAhg== + dependencies: + "@babel/runtime" "^7.3.1" + crypto-browserify "3.12.0" + eth-lib "0.2.8" + lodash "^4.17.11" + scrypt.js "0.2.0" + uuid "3.3.2" + web3-core "1.0.0-beta.50" + web3-core-helpers "1.0.0-beta.50" + web3-core-method "1.0.0-beta.50" + web3-providers "1.0.0-beta.50" + web3-utils "1.0.0-beta.50" + +web3-eth-accounts@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.0.tgz#bb26d5446017700a13b75fc69a2b1226fe44f6bb" + integrity sha512-d/fUAL3F6HqstvEiBnZ1RwZ77/DytgF9d6A3mWVvPOUk2Pqi77PM0adRvsKvIWUaQ/k6OoCk/oXtbzaO7CyGpg== + dependencies: + any-promise "1.3.0" + crypto-browserify "3.12.0" + eth-lib "0.2.7" + scrypt.js "^0.3.0" + underscore "1.9.1" + uuid "3.3.2" + web3-core "1.2.0" + web3-core-helpers "1.2.0" + web3-core-method "1.2.0" + web3-utils "1.2.0" + +web3-eth-contract@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.50.tgz#bc6d4523347e113c74c5e1c6c78219eeb61d9182" + integrity sha512-X8R1+qIeD4Dbz1RmQa5m3K1suVFigNgd7EFMp6vVC3ULDjt4R6T0cRmFw/x51v3MQoT7s6Yd1KiEWIAt9IYG6w== + dependencies: + "@babel/runtime" "^7.3.1" + lodash "^4.17.11" + web3-core "1.0.0-beta.50" + web3-core-helpers "1.0.0-beta.50" + web3-core-method "1.0.0-beta.50" + web3-core-subscriptions "1.0.0-beta.50" + web3-eth-abi "1.0.0-beta.50" + web3-eth-accounts "1.0.0-beta.50" + web3-providers "1.0.0-beta.50" + web3-utils "1.0.0-beta.50" + +web3-eth-contract@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.0.tgz#8d1c235c6624b5df428969ea2e9c26337095f6f0" + integrity sha512-hfjozNbfsoMeR3QklfkwU0Mqcw6YRD4y1Cb1ghGWNhFy2+/sbvKcQNPPJDKFTde22PRzGQBWyh/nb422Sux4bQ== + dependencies: + underscore "1.9.1" + web3-core "1.2.0" + web3-core-helpers "1.2.0" + web3-core-method "1.2.0" + web3-core-promievent "1.2.0" + web3-core-subscriptions "1.2.0" + web3-eth-abi "1.2.0" + web3-utils "1.2.0" + +web3-eth-ens@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.0.0-beta.50.tgz#29304e42e2671ea755a19ab3f1011ad197f115da" + integrity sha512-UnhYcNuSNRBOBcbD5y8cTyRh5ENn65/GfZkxCDXAKBY6sD4GzMZNkD7kq+37/34cnZEzzQPPGd9jLZNLXOklyg== + dependencies: + "@babel/runtime" "^7.3.1" + eth-ens-namehash "2.0.8" + lodash "^4.17.11" + web3-core "1.0.0-beta.50" + web3-core-helpers "1.0.0-beta.50" + web3-core-method "1.0.0-beta.50" + web3-eth-abi "1.0.0-beta.50" + web3-eth-contract "1.0.0-beta.50" + web3-net "1.0.0-beta.50" + web3-providers "1.0.0-beta.50" + web3-utils "1.0.0-beta.50" + +web3-eth-ens@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.0.tgz#af66308542f4acfa09ccd3ce370e3ad2de20ec30" + integrity sha512-kE6uHMLwH9dv+MZSKT7BcKXcQ6CcLP5m5mM44s2zg2e9Rl20F3J6R3Ik6sLc/w2ywdCwTe/Z22yEstHXQwu5ig== + dependencies: + eth-ens-namehash "2.0.8" + underscore "1.9.1" + web3-core "1.2.0" + web3-core-helpers "1.2.0" + web3-core-promievent "1.2.0" + web3-eth-abi "1.2.0" + web3-eth-contract "1.2.0" + web3-utils "1.2.0" + +web3-eth-iban@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.50.tgz#311ea9422369ecbde6316e10a34de9fb07994cd6" + integrity sha512-rW5fpUUW3WaToPxBXNnqTfj5dh2BJ+9uognYAfThh2WWR1+EwWZethsKS/PyU6Jn9uA5p/kQoUIP0JKaeBm80Q== + dependencies: + "@babel/runtime" "^7.3.1" + bn.js "4.11.8" + web3-utils "1.0.0-beta.50" + +web3-eth-iban@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.0.tgz#1bece9cebf817dca82fa03230203351f4f263866" + integrity sha512-6DzTx/cvIgEvxadhJjLGpsuDUARA4RKskNOuwWYUsUODcPb50rsfMmRkHhGtLss/sNXVE5gNjbT9rX3TDqy2tg== + dependencies: + bn.js "4.11.8" + web3-utils "1.2.0" + +web3-eth-personal@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.50.tgz#891f55bb93c2e38918be085dcb295634a59b31b1" + integrity sha512-52dS24YfJxx/Uy21RKj2m5rjag1kktdy5rY/R9vDwWZRrJkxfDf058CvtRF+QsD7A6QVxkHCZ9YwEWnLCLW9Cw== + dependencies: + "@babel/runtime" "^7.3.1" + web3-core "1.0.0-beta.50" + web3-core-helpers "1.0.0-beta.50" + web3-core-method "1.0.0-beta.50" + web3-net "1.0.0-beta.50" + web3-providers "1.0.0-beta.50" + web3-utils "1.0.0-beta.50" + +web3-eth-personal@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.0.tgz#7194f519c870d720eee1349d867408004f0f78af" + integrity sha512-8QdcaT6dbdiMC8zEqvDuij8XeI34r2GGdQYGvYBP2UgCm15EZBHgewxO30A+O+j2oIW1/Hu60zP5upnhCuA1Dw== + dependencies: + web3-core "1.2.0" + web3-core-helpers "1.2.0" + web3-core-method "1.2.0" + web3-net "1.2.0" + web3-utils "1.2.0" + +web3-eth@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.0.0-beta.50.tgz#6da9246d36d65ba7ff03209419c571359eda0e0a" + integrity sha512-ojsddEclIdu+C3hfRrLVJK0rcxt2O+Yj7c3b4YEzZQ9+Kd/HaSZfeSpUgKojgmFhUUiCCRTEc2holWtQ+Lx4gQ== + dependencies: + "@babel/runtime" "^7.3.1" + eth-lib "0.2.8" + rxjs "^6.4.0" + web3-core "1.0.0-beta.50" + web3-core-helpers "1.0.0-beta.50" + web3-core-method "1.0.0-beta.50" + web3-core-subscriptions "1.0.0-beta.50" + web3-eth-abi "1.0.0-beta.50" + web3-eth-accounts "1.0.0-beta.50" + web3-eth-contract "1.0.0-beta.50" + web3-eth-ens "1.0.0-beta.50" + web3-eth-iban "1.0.0-beta.50" + web3-eth-personal "1.0.0-beta.50" + web3-net "1.0.0-beta.50" + web3-providers "1.0.0-beta.50" + web3-utils "1.0.0-beta.50" + +web3-eth@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.0.tgz#ac8d3409356538d2fe1cb6151036b724eace76f6" + integrity sha512-GP1+hHS/IVW1tAOIDS44PxCpvSl9PBU/KAB40WgP27UMvSy43LjHxGlP6hQQOdIfmBLBTvGvn2n+Z5kW2gzAzg== + dependencies: + underscore "1.9.1" + web3-core "1.2.0" + web3-core-helpers "1.2.0" + web3-core-method "1.2.0" + web3-core-subscriptions "1.2.0" + web3-eth-abi "1.2.0" + web3-eth-accounts "1.2.0" + web3-eth-contract "1.2.0" + web3-eth-ens "1.2.0" + web3-eth-iban "1.2.0" + web3-eth-personal "1.2.0" + web3-net "1.2.0" + web3-utils "1.2.0" + +web3-net@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.0.0-beta.50.tgz#1ca188b9210da6ae560bbd35a2b6dea1d2e68da7" + integrity sha512-T9aBrWYzCeqZTTJlljonTm8x1tEjHT1uBqcdvEYZoyCS1Xxc+zCNBqP4SBfdcfwCeGohhI7bRx9qX1JjYH3cRA== + dependencies: + "@babel/runtime" "^7.3.1" + lodash "^4.17.11" + web3-core "1.0.0-beta.50" + web3-core-helpers "1.0.0-beta.50" + web3-core-method "1.0.0-beta.50" + web3-providers "1.0.0-beta.50" + web3-utils "1.0.0-beta.50" + +web3-net@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.0.tgz#9e99c4326a28712451dc4d45f3acf26c1d4b3219" + integrity sha512-7iD8C6vvx8APXPMmlpPLGWjn4bsXHzd3BTdFzKjkoYjiiVFJdVAbY3j1BwN/6tVQu8Ay7sDpV2EdTNub7GKbyw== + dependencies: + web3-core "1.2.0" + web3-core-method "1.2.0" + web3-utils "1.2.0" + +web3-providers-http@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.0.tgz#c6ebf9b6a23564439fa3c4a431cd6b405cc1ec0f" + integrity sha512-UrUn6JSz7NVCZ+0nZZtC4cmbl5JIi57w1flL1jN8jgkfdWDdErNvTkSwCt/QYdTQscMaUtWXDDOSAsVO6YC64g== + dependencies: + web3-core-helpers "1.2.0" + xhr2-cookies "1.1.0" + +web3-providers-ipc@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.0.tgz#98b8b8c9e77935dabfcf6d16e66c783f2429eac8" + integrity sha512-T2OSbiqu7+dahbGG5YFEQM5+FXdLVvaTCKmHXaQpw8IuL5hw7HELtyFOtHVudgDRyw0tJKxIfAiX/v2F1IL1fQ== + dependencies: + oboe "2.1.4" + underscore "1.9.1" + web3-core-helpers "1.2.0" + +web3-providers-ws@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.0.tgz#c45929f0d1e1743301372e6e604aab63e83f66e3" + integrity sha512-rnwGcCe6cev5A6eG5UBCQqPmkJVZMCrK+HN1AvUCco0OHD/0asGc9LuLbtkQIyznA6Lzetq/OOcaTOM4KeT11g== + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.0" + websocket "github:frozeman/WebSocket-Node#browserifyCompatible" + +web3-providers@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-providers/-/web3-providers-1.0.0-beta.50.tgz#41d7cd3c38f3b12f721c115fea1972a3d1904d25" + integrity sha512-p2xtr6N72pdXvND5dLdK1G9T/9qCQiKC2EYDPmimnqvoHWixmM3tlBl042swkHspHHVL60vXPKxB4UDaQE2hWQ== + dependencies: + "@babel/runtime" "^7.3.1" + "@types/node" "^10.12.18" + eventemitter3 "3.1.0" + lodash "^4.17.11" + url-parse "1.4.4" + websocket "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible" + xhr2-cookies "1.1.0" + +web3-shh@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.0.0-beta.50.tgz#e5a4a64b2308267b1635858e4adcc92eeee147f1" + integrity sha512-a46Gz/YQdF3HJ4XK7rZh6bJiP3IEq+BDAvdxD1jW54yKM2k3RGarOY8hanC1crxKE7E9Q1UUkrp1Vjrj8XSQuQ== + dependencies: + "@babel/runtime" "^7.3.1" + web3-core "1.0.0-beta.50" + web3-core-helpers "1.0.0-beta.50" + web3-core-method "1.0.0-beta.50" + web3-core-subscriptions "1.0.0-beta.50" + web3-net "1.0.0-beta.50" + web3-providers "1.0.0-beta.50" + web3-utils "1.0.0-beta.50" + +web3-shh@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.0.tgz#c07c306d761f70782c64e2b5b119db54e16f301f" + integrity sha512-VFjS8kvsQBodudFmIoVJWvDNZosONJZZnhvktngD3POu5dwbJmSCl6lzbLJ2C5XjR15dF+JvSstAkWbM+2sdPg== + dependencies: + web3-core "1.2.0" + web3-core-method "1.2.0" + web3-core-subscriptions "1.2.0" + web3-net "1.2.0" + +web3-utils@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.0.0-beta.50.tgz#ed12454d3d2727d3b77695c1899ad3abbef303af" + integrity sha512-xGhM/YkepK2x0iMYUl/sws58LzTbodjMGlhZxrCZLZxJ0DoaDyk3UdmZ6aCSCwVTFg4hlVj3doaIhWnwGfhhpQ== + dependencies: + "@babel/runtime" "^7.3.1" + "@types/bn.js" "^4.11.4" + "@types/node" "^10.12.18" + bn.js "4.11.8" + eth-lib "0.2.8" + ethjs-unit "^0.1.6" + lodash "^4.17.11" + number-to-bn "1.7.0" + randomhex "0.1.5" + utf8 "2.1.1" + +web3-utils@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.0.tgz#1f11b05d173b757d3f5ba32cb90b375a487d3bf0" + integrity sha512-tI1low8ICoaWU2c53cikH0rsksKuIskI2nycH5E5sEXxxl9/BOD3CeDDBFbxgNPQ+bpDevbR7gXNEDB7Ud4G9g== + dependencies: + bn.js "4.11.8" + eth-lib "0.2.7" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randomhex "0.1.5" + underscore "1.9.1" + utf8 "3.0.0" + +web3@1.0.0-beta.50: + version "1.0.0-beta.50" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.0.0-beta.50.tgz#a82db1ac519e68696363eee46d9b233f52f37eed" + integrity sha512-N4YqT1jl2tZYNWiLk5gA5BMchHJaG76d65z899DT9UTR4iI6mfqe1QIE+1YLII1x+uE8ohFzBq/aaZ8praLeoA== + dependencies: + "@babel/runtime" "^7.3.1" + "@types/node" "^10.12.18" + web3-bzz "1.0.0-beta.50" + web3-core "1.0.0-beta.50" + web3-core-helpers "1.0.0-beta.50" + web3-core-method "1.0.0-beta.50" + web3-eth "1.0.0-beta.50" + web3-eth-personal "1.0.0-beta.50" + web3-net "1.0.0-beta.50" + web3-providers "1.0.0-beta.50" + web3-shh "1.0.0-beta.50" + web3-utils "1.0.0-beta.50" + +web3@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.0.tgz#ef9c43a99eac348a85c09179690290d45a96a5f2" + integrity sha512-iFrVAexsopX97x0ofBU/7HrCxzovf624qBkjBUeHZDf/G3Sb4tMQtjkCRc5lgVvzureq5SCqDiFDcqnw7eJ0bA== + dependencies: + web3-bzz "1.2.0" + web3-core "1.2.0" + web3-eth "1.2.0" + web3-eth-personal "1.2.0" + web3-net "1.2.0" + web3-shh "1.2.0" + web3-utils "1.2.0" + +websocket@^1.0.28: + version "1.0.28" + resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.28.tgz#9e5f6fdc8a3fe01d4422647ef93abdd8d45a78d3" + integrity sha512-00y/20/80P7H4bCYkzuuvvfDvh+dgtXi5kzDf3UcZwN6boTYaKvsrtZ5lIYm1Gsg48siMErd9M4zjSYfYFHTrA== + dependencies: + debug "^2.2.0" + nan "^2.11.0" + typedarray-to-buffer "^3.1.5" + yaeti "^0.0.6" + +"websocket@git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible": + version "1.0.26" + resolved "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" + dependencies: + debug "^2.2.0" + nan "^2.3.3" + typedarray-to-buffer "^3.1.2" + yaeti "^0.0.6" + +"websocket@github:frozeman/WebSocket-Node#browserifyCompatible": + version "1.0.26" + uid "6c72925e3f8aaaea8dc8450f97627e85263999f2" + resolved "https://codeload.github.com/frozeman/WebSocket-Node/tar.gz/6c72925e3f8aaaea8dc8450f97627e85263999f2" + dependencies: + debug "^2.2.0" + nan "^2.3.3" + typedarray-to-buffer "^3.1.2" + yaeti "^0.0.6" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@^1.1.1, which@^1.2.14, which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +widest-line@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" + integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA== + dependencies: + string-width "^2.1.1" + +wordwrap@^1.0.0, wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + integrity sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA== + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +ws@^3.0.0: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + +xdg-basedir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= + +xhr-request-promise@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.2.tgz#343c44d1ee7726b8648069682d0f840c83b4261d" + integrity sha1-NDxE0e53JrhkgGloLQ+EDIO0Jh0= + dependencies: + xhr-request "^1.0.1" + +xhr-request@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" + integrity sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA== + dependencies: + buffer-to-arraybuffer "^0.0.5" + object-assign "^4.1.1" + query-string "^5.0.1" + simple-get "^2.7.0" + timed-out "^4.0.1" + url-set-query "^1.0.0" + xhr "^2.0.4" + +xhr2-cookies@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" + integrity sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg= + dependencies: + cookiejar "^2.1.1" + +xhr@^2.0.4, xhr@^2.3.3: + version "2.5.0" + resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.5.0.tgz#bed8d1676d5ca36108667692b74b316c496e49dd" + integrity sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ== + dependencies: + global "~4.3.0" + is-function "^1.0.1" + parse-headers "^2.0.0" + xtend "^4.0.0" + +xml@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= + +xmlhttprequest@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" + integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw= + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yaeti@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" + integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc= + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + +yargs-parser@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" + integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ== + dependencies: + camelcase "^4.1.0" + +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + integrity sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc= + dependencies: + camelcase "^4.1.0" + +yargs@11.1.0, yargs@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" + integrity sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A== + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + +yargs@^10.0.3: + version "10.1.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5" + integrity sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig== + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^8.1.0" + +yauzl@^2.4.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0"