├── .circleci
└── config.yml
├── .example.env
├── .gitattributes
├── .gitignore
├── .prettierignore
├── .solcover.js
├── LICENSE
├── README.md
├── api.md
├── audit_scope.md
├── buidler.config.js
├── contracts
├── AaveHandler.sol
├── CompoundHandler.sol
├── DForceLendingHandler.sol
├── DForceLendingHandlerSingle.sol
├── DToken.sol
├── DTokenController.sol
├── DTokenHP.sol
├── DTokenProxy.sol
├── Dispatcher.sol
├── Handler.sol
├── InternalHandler.sol
├── Migrations.sol
├── MoneyMarketHandler.sol
├── USRHandler.sol
├── UniswapSwapModel.sol
├── VenusHandler.sol
├── assets
│ ├── USDC
│ │ └── FiatTokenV1.sol
│ ├── USDT.sol
│ └── USDx.sol
├── helper
│ ├── CompBalance.sol
│ └── DTokenCommonData.sol
├── interface
│ ├── IAave.sol
│ ├── ICompound.sol
│ ├── IDForceLending.sol
│ ├── IDToken.sol
│ ├── IDTokenController.sol
│ ├── IDispatcher.sol
│ ├── IDispatcherView.sol
│ ├── IERC20.sol
│ ├── IHandler.sol
│ ├── IHandlerView.sol
│ ├── ILendFMe.sol
│ ├── IMoneyMarket.sol
│ ├── IUSR.sol
│ ├── IUniswapV2Router01.sol
│ ├── IUniswapV2Router02.sol
│ └── IVenus.sol
├── library
│ ├── DSAuth.sol
│ ├── DSGuard.sol
│ ├── ERC20SafeTransfer.sol
│ ├── Pausable.sol
│ ├── ReentrancyGuard.sol
│ └── SafeMath.sol
└── mock
│ ├── AaveProtocolMock.sol
│ ├── CTokenMock.sol
│ ├── DispatcherMock.sol
│ ├── TestERC20.sol
│ ├── TestHandlerMock.sol
│ ├── USRMock.sol
│ └── iTokenMock.sol
├── migrations
├── 1_deploy_contracts.js
├── 3_deploy_dForce_implementation.js
├── 4_deploy_dforce_handler_proxy.js
└── 5_config_for_dforce_handler.js
├── package.json
├── test
├── testAaveHandler.js
├── testAaveHandlerMock.js
├── testCompoundHandlerMock.js
├── testDForceHandlerMock.js
├── testDToken.js
├── testDTokenController.js
├── testDTokenIntegration.js
├── testDTokenOther.js
├── testDispatcher.js
├── testInternalHandler.js
├── testUSRHandlerMock.js
├── testUniswapSwapModel.js
├── testUserBehavior.js
└── testdUSDx.js
├── truffle-config.js
└── web-dapp
├── .gitignore
├── build.zip
├── config
├── env.js
├── getHttpsConfig.js
├── jest
│ ├── cssTransform.js
│ └── fileTransform.js
├── modules.js
├── paths.js
├── pnpTs.js
├── webpack.config.js
└── webpackDevServer.config.js
├── note.js
├── package.json
├── public
├── favicon.ico
└── index.html
├── scripts
├── build.js
├── start.js
└── test.js
└── src
├── App-bsc.js
├── App.js
├── App.scss
├── App.test.js
├── abi
├── DTokenCommonDataABI.json
├── address_map.json
├── baseData.json
├── constance.json
├── env.js
├── tokensABI.json
└── tokensABI_d.json
├── admin.js
├── component
├── FAQ
│ ├── components
│ │ └── SvgIcon
│ │ │ └── index.jsx
│ ├── index.js
│ ├── static
│ │ └── css
│ │ │ └── main.scss
│ └── svg
│ │ ├── collapse.svg
│ │ ├── fqa1.svg
│ │ ├── fqa2.svg
│ │ ├── fqa3.svg
│ │ ├── fqa4.svg
│ │ ├── fqa5.svg
│ │ ├── fqa6.svg
│ │ ├── fqa7.svg
│ │ └── unfold.svg
├── Home
│ ├── Item-bsc.jsx
│ ├── Item.jsx
│ ├── home.scss
│ └── index.jsx
├── SvgIcon
│ ├── index.jsx
│ └── style.scss
├── history-bsc.js
├── history.js
├── history.scss
├── top.js
└── top.scss
├── entry.js
├── header.scss
├── icons
├── index.js
└── svg
│ ├── DAI.svg
│ ├── USDC.svg
│ ├── USDT.svg
│ ├── content.svg
│ ├── operation.svg
│ └── room.svg
├── images
├── BTC.svg
├── BUSD.svg
├── DAI.svg
├── Discord.svg
├── HBTC.png
├── HBTC.svg
├── HUSD.svg
├── LinkedIn.svg
├── Reddit.svg
├── TUSD.svg
├── USDC.svg
├── USDT.svg
├── USDx.svg
├── UUDD.svg
├── WBTC.svg
├── WETH.svg
├── Youtube.svg
├── arrow-down.svg
├── arrow_d.svg
├── arrow_down.svg
├── close-new.svg
├── close.svg
├── erweima.png
├── exchange.svg
├── exchange_mob.svg
├── imBTC.svg
├── is_selected.svg
├── lock.svg
├── logo-dforce.svg
├── logo-xswap.svg
├── logo_exchange.svg
├── logo_exchange_fail.svg
├── logo_exchange_mint.svg
├── logo_exchange_pendding.svg
├── logo_exchange_redeem.svg
├── medium.svg
├── no-history.svg
├── no_support.svg
├── pax.png
├── show-tips.svg
├── telegram.svg
├── twitter.svg
├── up.svg
├── wallet-metamask.svg
├── weixin.svg
└── witch.svg
├── index.css
├── index.js
├── language
├── en_US.js
└── zh_CN.js
├── logo.svg
├── serviceWorker.js
├── setupTests.js
├── style
├── admin.scss
├── main-content.scss
├── model.scss
└── tips.scss
├── utils-bsc.js
└── utils.js
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | docker:
5 | - image: circleci/node:10.16
6 | steps:
7 | - checkout
8 | - run:
9 | name: Install Builder and dependencies
10 | command: |
11 | npm install
12 | - run:
13 | name: Compile contracts
14 | command: |
15 | npx buidler compile
16 | - run:
17 | name: Run tests
18 | command: |
19 | npm run copy-uniswap-artifacts
20 | npx buidler test
21 | - run:
22 | name: Run coverage
23 | command: |
24 | npx buidler coverage --temp build
25 |
--------------------------------------------------------------------------------
/.example.env:
--------------------------------------------------------------------------------
1 | INFURA_APIKEY =
2 | PRIVATE_KEYS = '["75xx45", "85xx45"]'
3 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.sol linguist-language=Solidity
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
3 |
4 | # dependencies
5 | node_modules
6 | package-lock.json
7 | /.pnp
8 | .pnp.js
9 |
10 | # coverage
11 | /coverage
12 | coverage.*
13 | local
14 |
15 |
16 | # production
17 | /build
18 | bundle.js
19 |
20 | # misc
21 | .DS_Store
22 | */.DS_Store
23 | .env
24 | .idea/
25 | .vscode/
26 |
27 | # Logs
28 | logs
29 | *.log
30 |
31 | # Database/Cache
32 | *.db
33 | artifacts
34 | cache
35 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | contracts/5/assets/DAI/*
2 |
--------------------------------------------------------------------------------
/.solcover.js:
--------------------------------------------------------------------------------
1 | var fs = require("fs");
2 |
3 | async function copyArtifacts() {
4 | const uniswapFiles = [
5 | ["v2-periphery/build/", "WETH9"],
6 | ["v2-core/build/", "UniswapV2Factory"],
7 | ["v2-core/build/", "UniswapV2Pair"],
8 | ["v2-periphery/build/", "UniswapV2Router02"],
9 | ];
10 |
11 | uniswapFiles.forEach((file) => {
12 | fs.copyFileSync(
13 | "./node_modules/@uniswap/" + file[0] + file[1] + ".json",
14 | "./build/" + file[1] + ".json"
15 | );
16 | });
17 | }
18 |
19 | module.exports = {
20 | onCompileComplete: copyArtifacts,
21 | skipFiles: [
22 | "assets",
23 | "markets",
24 | "library",
25 | "interface",
26 | "mock",
27 | "DTokenProxy.sol",
28 | "Migrations.sol",
29 | "MoneyMarketHandler.sol",
30 | ],
31 |
32 | mocha: {
33 | grep: "(Skipped in coverage)", // We have some cases need to be skipped
34 | invert: true, // Run the grep's inverse set.
35 | },
36 | };
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 dForceNetwork
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/api.md:
--------------------------------------------------------------------------------
1 | ### Send Transactions
2 |
3 | - mint(address \_dst, uint \_pie)
4 |
5 | - \_dst: account who will get dtoken.
6 | - \_pie: underlying token amount.
7 |
8 | - redeem(address \_src, uint \_wad)
9 |
10 | - \_src: account whose dtoken will burn from.
11 | - \_wad: dtoken amount to burn.
12 |
13 | - redeemUnderlying(address \_src, uint \_pie)
14 |
15 | - \_src: account whose dtoken will burn from.
16 | - \_pie: underlying token amount to withdraw.
17 |
18 | - approve(address \_spender, uint \_wad) returns (bool)
19 |
20 | - \_spender: approved spender.
21 | - \_wad: amount to approve.
22 | - returns: true if success.
23 |
24 | - transfer(address \_dst, uint \_wad) returns (bool)
25 |
26 | - \_dst: recipient address.
27 | - \_wad: amount to transfer.
28 | - returns: true if success.
29 |
30 | - transferFrom(address \_src, address \_dst, uint \_wad) returns (bool)
31 |
32 | - \_src: sender address.
33 | - \_dst: recipient address.
34 | - \_wad: amount to transfer.
35 | - returns: true if success.
36 |
37 | ### call
38 |
39 | - name() returns (string)
40 |
41 | - returns: token name.
42 |
43 | - symbol() returns (string)
44 |
45 | - returns: token symbol.
46 |
47 | - decimals() returns (uint8)
48 |
49 | - returns: token decimals.
50 |
51 | - totalSupply() returns (uint)
52 |
53 | - returns: total dtoken anmount.
54 |
55 | - balanceOf(address \_account) returns (uint)
56 |
57 | - \_account: account address.
58 | - returns: dtoken balance of given account.
59 |
60 | - allowance(address \_owner, address \_spender) returns (uint)
61 |
62 | - \_owner: owner address.
63 | - \_spender: spender address.
64 | - returns: the amount which \_spender is still allowed to withdraw from \_owner.
65 |
66 | - currentExchangeRate() returns (uint)
67 |
68 | - returns: the most recent exchange rate, scaled by 1e18.
69 |
70 | - totalUnderlying() returns (uint)
71 |
72 | - returns: the total underlying token amount.
73 |
74 | - getRealLiquidity() returns (uint)
75 |
76 | - returns: current liquidity of the underlying token.
77 |
78 | - balanceOfUnderlying(address \_account) returns (uint)
79 |
80 | - \_account: account address.
81 | - returns: underlying token balance of given account.
82 |
83 | - getBaseData() returns (uint, uint, uint, uint, uint)
84 |
85 | - returns (decimals, exchangeRate, mintFeeRate, redeemFeeRate, totalUnderlying)
86 | - decimals: token decimals.
87 | - exchangeRate: the most recent exchange rate, scaled by 1e18.
88 | - mintFeeRate: the fee rate of mint(), scaled by 1e18.
89 | - redeemFeeRate: the fee rate of redeem()/redeemUnderlying(), scaled by 1e18.
90 | - totalUnderlying: the total underlying token amount.
91 |
92 | - originationFee(bytes4 \_sig) returns (uint)
93 |
94 | - \_sig: function signature to query.
95 | - returns: fee, scaled by 1e18.
96 |
97 | - paused() returns (bool)
98 |
99 | - returns: true if paused, false if not paused.
100 |
101 | - feeRecipient() returns (address)
102 |
103 | - returns: fee receiving address.
104 |
--------------------------------------------------------------------------------
/audit_scope.md:
--------------------------------------------------------------------------------
1 | ### Audit Scope:
2 |
3 | - DTokenProxy.sol
4 |
5 | - DToken.sol
6 |
7 | - DTokenController.sol
8 |
9 | - Dispatcher.sol
10 |
11 | - InternalHandler.sol
12 |
13 | - CompoundHandler.sol
14 |
15 | - AaveHandler.sol
16 |
17 | ### Audit Target:
18 |
19 | - If the contract upgradability logic is correct.
20 |
21 | - If the underlying token in dToken is secure and not exposure to any risks.
22 |
23 | - If dToken is compatible with underlying tokens such as USDx/USDT(Non-standard ERC20)/USDC/DAI/TUSD/PAX/BUSD/HUSD/HBTC/rBTC/WBTC/imBTC(ERC777), especially non-standard erc20 and erc777 compliant token.
24 |
25 | - If able to handle governance token of underlying supported protocols (i.e Compound).
26 |
27 | - If handler are able to properly integrate with lending protocols, such as compound / aave.
28 |
29 | - If the calculation of dToken exchange rate is correct, especially when allocated to Compound and interacting with cToken, is there any possible for exchange rate manipulation and attack vector.
30 |
31 | * If allocation strategy (when deposit) and withdraw strategy(when burn/redeem) are implemented correct.
32 |
33 | * If rebalance functionality is properly implemented.
34 |
35 | * If authority functionality is properly implemented.
36 |
37 | * If dToken is exposed to any Flashloan attack vector(interest rate calculation difference of supported protocols)
38 |
39 | * Hint: resetHandlers function is kind of recovery tool, internalHander must be set to index 0 position.
40 |
--------------------------------------------------------------------------------
/buidler.config.js:
--------------------------------------------------------------------------------
1 | // For unit test
2 | usePlugin("@nomiclabs/buidler-truffle5");
3 |
4 | usePlugin("@nomiclabs/buidler-waffle");
5 | // usePlugin("@nomiclabs/builder-ganache");
6 | usePlugin("buidler-gas-reporter");
7 | usePlugin("solidity-coverage");
8 |
9 | // // For scripts
10 | // // usePlugin("@nomiclabs/builder-ethers");
11 |
12 | // // Faster compilation
13 | // usePlugin("@nomiclabs/builder-docker-solc");
14 |
15 | // You have to export an object to set up your config
16 | // This object can have the following optional entries:
17 | // defaultNetwork, networks, solc, and paths.
18 | // Go to https://buidler.dev/config/ to learn more
19 | module.exports = {
20 | // This is a sample solc configuration that specifies which version of solc to use
21 | solc: {
22 | version: "0.5.12",
23 | optimizer: {
24 | enabled: true,
25 | runs: 200,
26 | },
27 | },
28 | paths: {
29 | sources: "./contracts",
30 | },
31 | gasReporter: {
32 | enabled: process.env.REPORT_GAS ? true : false,
33 | // enabled: true,
34 | currency: "USD",
35 | },
36 | mocha: { timeout: 50000 },
37 | };
38 |
--------------------------------------------------------------------------------
/contracts/DTokenController.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | import "./library/DSAuth.sol";
4 |
5 | contract DTokenController is DSAuth {
6 | bool private initialized; // Flags for initializing data
7 |
8 | mapping(address => address) internal dTokens;
9 |
10 | event NewMappingdToken(
11 | address indexed token,
12 | address indexed mappingdToken
13 | );
14 |
15 | constructor() public {
16 | initialize();
17 | }
18 |
19 | // --- Init ---
20 | // This function is used with contract proxy, do not modify this function.
21 | function initialize() public {
22 | require(!initialized, "initialize: Already initialized!");
23 | owner = msg.sender;
24 | initialized = true;
25 | }
26 |
27 | /**
28 | * @dev Adds new mapping: token => dToken.
29 | */
30 | function setdTokensRelation(
31 | address[] memory _tokens,
32 | address[] memory _mappingdTokens
33 | ) public auth {
34 | require(
35 | _tokens.length == _mappingdTokens.length,
36 | "setdTokensRelation: Array length do not match!"
37 | );
38 | for (uint256 i = 0; i < _tokens.length; i++) {
39 | _setdTokenRelation(_tokens[i], _mappingdTokens[i]);
40 | }
41 | }
42 |
43 | function _setdTokenRelation(address _token, address _mappingdToken)
44 | internal
45 | {
46 | require(
47 | dTokens[_token] == address(0x0),
48 | "_setdTokenRelation: Has set!"
49 | );
50 | dTokens[_token] = _mappingdToken;
51 | emit NewMappingdToken(_token, _mappingdToken);
52 | }
53 |
54 | /**
55 | * @dev Updates existing mapping: token => dToken.
56 | */
57 | function updatedTokenRelation(address _token, address _mappingdToken)
58 | external
59 | auth
60 | {
61 | require(
62 | dTokens[_token] != address(0x0),
63 | "updatedTokenRelation: token does not exist!"
64 | );
65 | dTokens[_token] = _mappingdToken;
66 | emit NewMappingdToken(_token, _mappingdToken);
67 | }
68 |
69 | function getDToken(address _token) external view returns (address) {
70 | return dTokens[_token];
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/contracts/Handler.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | import "./library/Pausable.sol";
4 | import "./library/ERC20SafeTransfer.sol";
5 | import "./library/SafeMath.sol";
6 | import "./interface/IDTokenController.sol";
7 |
8 | contract Handler is ERC20SafeTransfer, Pausable {
9 | using SafeMath for uint256;
10 | bool private initialized; // Flags for initializing data
11 | address public dTokenController; // dToken mapping contract
12 |
13 | mapping(address => bool) private tokensEnable; // Supports token or not
14 |
15 | event NewdTokenAddresses(
16 | address indexed originalDToken,
17 | address indexed newDToken
18 | );
19 | event DisableToken(address indexed underlyingToken);
20 | event EnableToken(address indexed underlyingToken);
21 |
22 | // --- Init ---
23 | // This function is used with contract proxy, do not modify this function.
24 | function initialize(address _dTokenController) public {
25 | require(!initialized, "initialize: Already initialized!");
26 | owner = msg.sender;
27 | dTokenController = _dTokenController;
28 | initialized = true;
29 | }
30 |
31 | /**
32 | * @dev Update dToken mapping contract.
33 | * @param _newDTokenController The new dToken mapping contact.
34 | */
35 | function setDTokenController(address _newDTokenController) external auth {
36 | require(
37 | _newDTokenController != dTokenController,
38 | "setDTokenController: The same dToken mapping contract address!"
39 | );
40 | address _originalDTokenController = dTokenController;
41 | dTokenController = _newDTokenController;
42 | emit NewdTokenAddresses(
43 | _originalDTokenController,
44 | _newDTokenController
45 | );
46 | }
47 |
48 | /**
49 | * @dev Authorized function to disable some underlying tokens.
50 | * @param _underlyingTokens Tokens to disable.
51 | */
52 | function disableTokens(address[] calldata _underlyingTokens) external auth {
53 | for (uint256 i = 0; i < _underlyingTokens.length; i++) {
54 | _disableToken(_underlyingTokens[i]);
55 | }
56 | }
57 |
58 | /**
59 | * @dev Authorized function to enable some underlying tokens.
60 | * @param _underlyingTokens Tokens to enable.
61 | */
62 | function enableTokens(address[] calldata _underlyingTokens) external auth {
63 | for (uint256 i = 0; i < _underlyingTokens.length; i++) {
64 | _enableToken(_underlyingTokens[i]);
65 | }
66 | }
67 |
68 | function _disableToken(address _underlyingToken) internal {
69 | require(
70 | tokensEnable[_underlyingToken],
71 | "disableToken: Has been disabled!"
72 | );
73 | tokensEnable[_underlyingToken] = false;
74 | emit DisableToken(_underlyingToken);
75 | }
76 |
77 | function _enableToken(address _underlyingToken) internal {
78 | require(
79 | !tokensEnable[_underlyingToken],
80 | "enableToken: Has been enabled!"
81 | );
82 | tokensEnable[_underlyingToken] = true;
83 | emit EnableToken(_underlyingToken);
84 | }
85 |
86 | /**
87 | * @dev The _underlyingToken approves to dToken contract.
88 | * @param _underlyingToken Token address to approve.
89 | */
90 | function approve(address _underlyingToken, uint256 amount) public auth {
91 | address _dToken = IDTokenController(dTokenController).getDToken(
92 | _underlyingToken
93 | );
94 |
95 | require(
96 | doApprove(_underlyingToken, _dToken, amount),
97 | "approve: Approve dToken failed!"
98 | );
99 | }
100 |
101 | /**
102 | * @dev Support token or not.
103 | * @param _underlyingToken Token to check.
104 | */
105 | function tokenIsEnabled(address _underlyingToken)
106 | public
107 | view
108 | returns (bool)
109 | {
110 | return tokensEnable[_underlyingToken];
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/contracts/InternalHandler.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | import "./Handler.sol";
4 |
5 | contract InternalHandler is Handler {
6 | constructor(address _dTokenController) public {
7 | super.initialize(_dTokenController);
8 | }
9 |
10 | /**
11 | * @dev Deposit token to market, only called by dToken contract.
12 | * @param _underlyingToken Token to deposit.
13 | * @return The actual deposited token amount.
14 | */
15 | function deposit(address _underlyingToken, uint256 _amount)
16 | external
17 | view
18 | whenNotPaused
19 | auth
20 | returns (uint256)
21 | {
22 | require(
23 | tokenIsEnabled(_underlyingToken),
24 | "deposit: Token is disabled!"
25 | );
26 | return _amount;
27 | }
28 |
29 | /**
30 | * @dev Withdraw token from market, but only for dToken contract.
31 | * @param _underlyingToken Token to withdraw.
32 | * @param _amount Token amount to withdraw.
33 | * @return The actual withdrown token amount.
34 | */
35 | function withdraw(address _underlyingToken, uint256 _amount)
36 | external
37 | view
38 | whenNotPaused
39 | auth
40 | returns (uint256)
41 | {
42 | return
43 | _amount == uint256(-1)
44 | ? IERC20(_underlyingToken).balanceOf(address(this))
45 | : _amount;
46 | }
47 |
48 | /**
49 | * @dev Total balance with any accumulated interest for `_underlyingToken` belonging to `handler`.
50 | * @param _underlyingToken Token to get balance.
51 | */
52 | function getRealBalance(address _underlyingToken)
53 | public
54 | view
55 | returns (uint256)
56 | {
57 | return IERC20(_underlyingToken).balanceOf(address(this));
58 | }
59 |
60 | /**
61 | * @dev The maximum withdrawable amount of token `_underlyingToken` in the market.
62 | * @param _underlyingToken Token to get liquidity.
63 | */
64 | function getRealLiquidity(address _underlyingToken)
65 | public
66 | view
67 | returns (uint256)
68 | {
69 | return IERC20(_underlyingToken).balanceOf(address(this));
70 | }
71 |
72 | /***************************************************/
73 | /*** View Interfaces For Backwards compatibility ***/
74 | /***************************************************/
75 |
76 | /**
77 | * @dev Total balance with any accumulated interest for `_underlyingToken` belonging to `handler`.
78 | * @param _underlyingToken Token to get balance.
79 | */
80 | function getBalance(address _underlyingToken)
81 | external
82 | view
83 | returns (uint256)
84 | {
85 | return getRealBalance(_underlyingToken);
86 | }
87 |
88 | /**
89 | * @dev The maximum withdrawable amount of token `_underlyingToken` in the market.
90 | * @param _underlyingToken Token to get liquidity.
91 | */
92 | function getLiquidity(address _underlyingToken)
93 | external
94 | view
95 | returns (uint256)
96 | {
97 | return getRealLiquidity(_underlyingToken);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/contracts/Migrations.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.4.21 <0.7.0;
2 |
3 | contract Migrations {
4 | address public owner;
5 | uint256 public last_completed_migration;
6 |
7 | modifier restricted() {
8 | if (msg.sender == owner) _;
9 | }
10 |
11 | constructor() public {
12 | owner = msg.sender;
13 | }
14 |
15 | function setCompleted(uint256 completed) public restricted {
16 | last_completed_migration = completed;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/contracts/UniswapSwapModel.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | import "./interface/IUniswapV2Router02.sol";
4 | import "./interface/IDToken.sol";
5 | import "./interface/IDispatcher.sol";
6 | import "./library/ERC20SafeTransfer.sol";
7 |
8 | interface ISwapModel {
9 | function swap(address reward, uint256 amount) external;
10 | }
11 |
12 | contract UniswapSwapModel is ISwapModel, ERC20SafeTransfer {
13 | event Swap(
14 | address tokenIn,
15 | uint256 amountIn,
16 | address tokenOut,
17 | uint256 amountOut
18 | );
19 |
20 | function swap(address _token, uint256 _amount) external {
21 | IDToken _dtoken = IDToken(address(this));
22 |
23 | // Trasfer the swapped token to internal handler
24 | address _recipient = IDispatcher(_dtoken.dispatcher()).defaultHandler();
25 |
26 | // Swap to underlying token
27 | address _underlying = _dtoken.token();
28 |
29 | uint256[] memory amounts = _swap(
30 | _token,
31 | _underlying,
32 | _recipient,
33 | _amount
34 | );
35 |
36 | require(amounts.length >= 2, "swap: swap returned wrong amounts");
37 |
38 | emit Swap(_token, amounts[0], _underlying, amounts[amounts.length - 1]);
39 | }
40 |
41 | function _swap(
42 | address _tokenA,
43 | address _tokenB,
44 | address _to,
45 | uint256 _amount
46 | ) internal returns (uint256[] memory amounts) {
47 | // !!!! Hard code address for UniswapV2Router02,
48 | // Change it to corresponding address for mainnet or testnet
49 |
50 | // Mainnet and testnet
51 | // address router = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
52 |
53 | // Localhost for development, use accounts[accounts.length-1] to deploy
54 | address router = 0x4607B8eBBC7953d709238937844327EA107462F9;
55 |
56 | require(doApprove(_tokenA, router, _amount), "_swap: approve failed.");
57 |
58 | IUniswapV2Router02 _router = IUniswapV2Router02(router);
59 |
60 | // amountOutMin must be retrieved from an oracle of some kind
61 | uint256 _amountOutMin = 0;
62 | address[] memory _path = new address[](3);
63 |
64 | // We can add some intermediate token if the direct pair does not exist
65 | _path[0] = _tokenA;
66 | _path[1] = _router.WETH();
67 | _path[2] = _tokenB;
68 |
69 | return
70 | _router.swapExactTokensForTokens(
71 | _amount,
72 | _amountOutMin,
73 | _path,
74 | _to,
75 | block.timestamp
76 | );
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/contracts/interface/IAave.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | // 0x398eC7346DcD622eDc5ae82352F02bE94C62d119
4 | interface LendingPool {
5 | function deposit(
6 | address _reserve,
7 | uint256 _amount,
8 | uint16 _referralCode
9 | ) external payable;
10 | }
11 |
12 | interface AToken {
13 | function principalBalanceOf(address _user) external view returns (uint256);
14 |
15 | function redeem(uint256 _amount) external;
16 | }
17 |
18 | // 0x3dfd23A6c5E8BbcFc9581d2E864a68feb6a076d3
19 | interface LendingPoolCore {
20 | function getReserveATokenAddress(address _reserve)
21 | external
22 | view
23 | returns (address);
24 |
25 | function getReserveAvailableLiquidity(address _reserve)
26 | external
27 | view
28 | returns (uint256);
29 | }
30 |
--------------------------------------------------------------------------------
/contracts/interface/ICompound.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | interface ICompound {
4 | // uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
5 | function mint(uint256 mintAmount) external returns (uint256);
6 |
7 | // uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
8 | function redeemUnderlying(uint256 redeemAmount) external returns (uint256);
9 |
10 | function redeem(uint256 redeemTokens) external returns (uint256);
11 |
12 | // uint(Error.NO_ERROR), cTokenBalance, borrowBalance, exchangeRateMantissa
13 | function getAccountSnapshot(address account)
14 | external
15 | view
16 | returns (
17 | uint256,
18 | uint256,
19 | uint256,
20 | uint256
21 | );
22 |
23 | function balanceOfUnderlying(address owner) external returns (uint256);
24 |
25 | function getCash() external view returns (uint256);
26 | }
27 |
--------------------------------------------------------------------------------
/contracts/interface/IDForceLending.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | interface IController {
4 | function hasiToken(address _iToken) external view returns (bool);
5 | function rewardDistributor() external view returns (IRewardDistributor);
6 | }
7 |
8 | interface IRewardDistributor {
9 | function claimAllReward(address[] calldata _holders) external;
10 | function claimReward(address[] calldata _holders, address[] calldata _iTokens) external;
11 |
12 | function rewardToken() external view returns (address);
13 | }
14 |
15 | interface IiToken {
16 | function mint(address _recipient, uint256 _mintAmount) external;
17 |
18 | function redeem(address _from, uint256 _redeemiToken) external;
19 |
20 | function redeemUnderlying(address _from, uint256 _redeemUnderlying) external;
21 |
22 | function balanceOfUnderlying(address _account) external returns (uint256);
23 |
24 | function exchangeRateStored() external view returns (uint256);
25 |
26 | function getCash() external view returns (uint256);
27 |
28 | function controller() external view returns (IController);
29 |
30 | function underlying() external view returns (address);
31 |
32 | function isiToken() external view returns (bool);
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/contracts/interface/IDTokenController.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | interface IDTokenController {
4 | function getDToken(address _token) external view returns (address);
5 | }
6 |
--------------------------------------------------------------------------------
/contracts/interface/IDispatcher.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | interface IDispatcher {
4 | function getHandlers()
5 | external
6 | view
7 | returns (address[] memory, uint256[] memory);
8 |
9 | function getDepositStrategy(uint256 _amount)
10 | external
11 | view
12 | returns (address[] memory, uint256[] memory);
13 |
14 | function getWithdrawStrategy(address _token, uint256 _amount)
15 | external
16 | returns (address[] memory, uint256[] memory);
17 |
18 | function isHandlerActive(address _handler) external view returns (bool);
19 |
20 | function defaultHandler() external view returns (address);
21 | }
22 |
--------------------------------------------------------------------------------
/contracts/interface/IDispatcherView.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | interface IDispatcherView {
4 | function getHandlers()
5 | external
6 | view
7 | returns (address[] memory, uint256[] memory);
8 |
9 | function getDepositStrategy(uint256 _amount)
10 | external
11 | view
12 | returns (address[] memory, uint256[] memory);
13 |
14 | function getWithdrawStrategy(address _token, uint256 _amount)
15 | external
16 | view
17 | returns (address[] memory, uint256[] memory);
18 |
19 | function isHandlerActive(address _handler) external view returns (bool);
20 |
21 | function defaultHandler() external view returns (address);
22 | }
23 |
--------------------------------------------------------------------------------
/contracts/interface/IERC20.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | /**
4 | * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
5 | * the optional functions; to access them see {ERC20Detailed}.
6 | */
7 | interface IERC20 {
8 | /**
9 | * @dev Returns the amount of tokens in existence.
10 | */
11 | function totalSupply() external view returns (uint256);
12 |
13 | /**
14 | * @dev Returns the amount of tokens owned by `account`.
15 | */
16 | function balanceOf(address account) external view returns (uint256);
17 |
18 | /**
19 | * @dev Moves `amount` tokens from the caller's account to `recipient`.
20 | *
21 | * Emits a {Transfer} event.
22 | */
23 | function transfer(address recipient, uint256 amount) external;
24 |
25 | /**
26 | * @dev Returns the remaining number of tokens that `spender` will be
27 | * allowed to spend on behalf of `owner` through {transferFrom}. This is
28 | * zero by default.
29 | *
30 | * This value changes when {approve} or {transferFrom} are called.
31 | */
32 | function allowance(address owner, address spender)
33 | external
34 | view
35 | returns (uint256);
36 |
37 | /**
38 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
39 | *
40 | * IMPORTANT: Beware that changing an allowance with this method brings the risk
41 | * that someone may use both the old and the new allowance by unfortunate
42 | * transaction ordering. One possible solution to mitigate this race
43 | * condition is to first reduce the spender's allowance to 0 and set the
44 | * desired value afterwards:
45 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
46 | *
47 | * Emits an {Approval} event.
48 | */
49 | function approve(address spender, uint256 amount) external;
50 |
51 | /**
52 | * @dev Moves `amount` tokens from `sender` to `recipient` using the
53 | * allowance mechanism. `amount` is then deducted from the caller's
54 | * allowance.
55 | *
56 | * Emits a {Transfer} event.
57 | */
58 | function transferFrom(
59 | address sender,
60 | address recipient,
61 | uint256 amount
62 | ) external;
63 |
64 | /**
65 | * @dev Emitted when `value` tokens are moved from one account (`from`) to
66 | * another (`to`).
67 | *
68 | * Note that `value` may be zero.
69 | */
70 | event Transfer(address indexed from, address indexed to, uint256 value);
71 |
72 | /**
73 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by
74 | * a call to {approve}. `value` is the new allowance.
75 | */
76 | event Approval(
77 | address indexed owner,
78 | address indexed spender,
79 | uint256 value
80 | );
81 |
82 | // This function is not a standard ERC20 interface, just for compitable with market.
83 | function decimals() external view returns (uint8);
84 | }
85 |
--------------------------------------------------------------------------------
/contracts/interface/IHandler.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | interface IHandler {
4 | function deposit(address _token, uint256 _amount)
5 | external
6 | returns (uint256);
7 |
8 | function withdraw(address _token, uint256 _amount)
9 | external
10 | returns (uint256);
11 |
12 | function getRealBalance(address _token) external returns (uint256);
13 |
14 | function getRealLiquidity(address _token) external returns (uint256);
15 |
16 | function getBalance(address _token) external view returns (uint256);
17 |
18 | function getLiquidity(address _token) external view returns (uint256);
19 |
20 | function paused() external view returns (bool);
21 |
22 | function tokenIsEnabled(address _underlyingToken)
23 | external
24 | view
25 | returns (bool);
26 | }
27 |
--------------------------------------------------------------------------------
/contracts/interface/IHandlerView.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | interface IHandlerView {
4 | function getRealBalance(address _token) external view returns (uint256);
5 |
6 | function getRealLiquidity(address _token) external view returns (uint256);
7 |
8 | function getBalance(address _token) external view returns (uint256);
9 |
10 | function getLiquidity(address _token) external view returns (uint256);
11 |
12 | function paused() external view returns (bool);
13 |
14 | function tokenIsEnabled(address _underlyingToken)
15 | external
16 | view
17 | returns (bool);
18 | }
19 |
--------------------------------------------------------------------------------
/contracts/interface/ILendFMe.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | interface ILendFMe {
4 | function supply(address _token, uint256 _amount) external returns (uint256);
5 |
6 | function withdraw(address _token, uint256 _amount)
7 | external
8 | returns (uint256);
9 |
10 | function getSupplyBalance(address _user, address _token)
11 | external
12 | view
13 | returns (uint256);
14 |
15 | function markets(address _token)
16 | external
17 | view
18 | returns (
19 | bool,
20 | uint256,
21 | address,
22 | uint256,
23 | uint256,
24 | uint256,
25 | uint256,
26 | uint256,
27 | uint256
28 | );
29 |
30 | function supplyBalances(address account, address token)
31 | external
32 | view
33 | returns (uint256, uint256);
34 | }
35 |
--------------------------------------------------------------------------------
/contracts/interface/IMoneyMarket.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | contract InterestRateModel {
4 | /**
5 | * @notice Gets the current supply interest rate based on the given asset, total cash and total borrows
6 | * @dev The return value should be scaled by 1e18, thus a return value of
7 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*.
8 | * @param asset The asset to get the interest rate of
9 | * @param cash The total cash of the asset in the market
10 | * @param borrows The total borrows of the asset in the market
11 | * @return Success or failure and the supply interest rate per block scaled by 10e18
12 | */
13 | function getSupplyRate(
14 | address asset,
15 | uint256 cash,
16 | uint256 borrows
17 | ) public view returns (uint256, uint256);
18 |
19 | /**
20 | * @notice Gets the current borrow interest rate based on the given asset, total cash and total borrows
21 | * @dev The return value should be scaled by 1e18, thus a return value of
22 | * `(true, 1000000000000)` implies an interest rate of 0.000001 or 0.0001% *per block*.
23 | * @param asset The asset to get the interest rate of
24 | * @param cash The total cash of the asset in the market
25 | * @param borrows The total borrows of the asset in the market
26 | * @return Success or failure and the borrow interest rate per block scaled by 10e18
27 | */
28 | function getBorrowRate(
29 | address asset,
30 | uint256 cash,
31 | uint256 borrows
32 | ) public view returns (uint256, uint256);
33 | }
34 |
35 | contract MoneyMarket {
36 | function markets(address asset)
37 | public
38 | view
39 | returns (
40 | bool,
41 | uint256,
42 | InterestRateModel,
43 | uint256,
44 | uint256,
45 | uint256,
46 | uint256,
47 | uint256,
48 | uint256
49 | );
50 |
51 | function oracle() public view returns (address);
52 | }
53 |
--------------------------------------------------------------------------------
/contracts/interface/IUSR.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | interface IUSR {
4 | // bool true:success, otherwise a failure (see ErrorReporter.sol for details)
5 | function mint(address account, uint256 mintAmount) external returns (bool);
6 |
7 | // bool true:success, otherwise a failure (see ErrorReporter.sol for details)
8 | function redeemUnderlying(address account, uint256 underlyingAmount)
9 | external
10 | returns (bool);
11 |
12 | function redeem(address account, uint256 amount) external returns (bool);
13 |
14 | function balanceOfUnderlying(address owner) external returns (uint256);
15 |
16 | function underlyingToken() external view returns (address);
17 | }
18 |
--------------------------------------------------------------------------------
/contracts/interface/IUniswapV2Router01.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | interface IUniswapV2Router01 {
4 | function factory() external pure returns (address);
5 |
6 | function WETH() external pure returns (address);
7 |
8 | function addLiquidity(
9 | address tokenA,
10 | address tokenB,
11 | uint256 amountADesired,
12 | uint256 amountBDesired,
13 | uint256 amountAMin,
14 | uint256 amountBMin,
15 | address to,
16 | uint256 deadline
17 | )
18 | external
19 | returns (
20 | uint256 amountA,
21 | uint256 amountB,
22 | uint256 liquidity
23 | );
24 |
25 | function addLiquidityETH(
26 | address token,
27 | uint256 amountTokenDesired,
28 | uint256 amountTokenMin,
29 | uint256 amountETHMin,
30 | address to,
31 | uint256 deadline
32 | )
33 | external
34 | payable
35 | returns (
36 | uint256 amountToken,
37 | uint256 amountETH,
38 | uint256 liquidity
39 | );
40 |
41 | function removeLiquidity(
42 | address tokenA,
43 | address tokenB,
44 | uint256 liquidity,
45 | uint256 amountAMin,
46 | uint256 amountBMin,
47 | address to,
48 | uint256 deadline
49 | ) external returns (uint256 amountA, uint256 amountB);
50 |
51 | function removeLiquidityETH(
52 | address token,
53 | uint256 liquidity,
54 | uint256 amountTokenMin,
55 | uint256 amountETHMin,
56 | address to,
57 | uint256 deadline
58 | ) external returns (uint256 amountToken, uint256 amountETH);
59 |
60 | function removeLiquidityWithPermit(
61 | address tokenA,
62 | address tokenB,
63 | uint256 liquidity,
64 | uint256 amountAMin,
65 | uint256 amountBMin,
66 | address to,
67 | uint256 deadline,
68 | bool approveMax,
69 | uint8 v,
70 | bytes32 r,
71 | bytes32 s
72 | ) external returns (uint256 amountA, uint256 amountB);
73 |
74 | function removeLiquidityETHWithPermit(
75 | address token,
76 | uint256 liquidity,
77 | uint256 amountTokenMin,
78 | uint256 amountETHMin,
79 | address to,
80 | uint256 deadline,
81 | bool approveMax,
82 | uint8 v,
83 | bytes32 r,
84 | bytes32 s
85 | ) external returns (uint256 amountToken, uint256 amountETH);
86 |
87 | function swapExactTokensForTokens(
88 | uint256 amountIn,
89 | uint256 amountOutMin,
90 | address[] calldata path,
91 | address to,
92 | uint256 deadline
93 | ) external returns (uint256[] memory amounts);
94 |
95 | function swapTokensForExactTokens(
96 | uint256 amountOut,
97 | uint256 amountInMax,
98 | address[] calldata path,
99 | address to,
100 | uint256 deadline
101 | ) external returns (uint256[] memory amounts);
102 |
103 | function swapExactETHForTokens(
104 | uint256 amountOutMin,
105 | address[] calldata path,
106 | address to,
107 | uint256 deadline
108 | ) external payable returns (uint256[] memory amounts);
109 |
110 | function swapTokensForExactETH(
111 | uint256 amountOut,
112 | uint256 amountInMax,
113 | address[] calldata path,
114 | address to,
115 | uint256 deadline
116 | ) external returns (uint256[] memory amounts);
117 |
118 | function swapExactTokensForETH(
119 | uint256 amountIn,
120 | uint256 amountOutMin,
121 | address[] calldata path,
122 | address to,
123 | uint256 deadline
124 | ) external returns (uint256[] memory amounts);
125 |
126 | function swapETHForExactTokens(
127 | uint256 amountOut,
128 | address[] calldata path,
129 | address to,
130 | uint256 deadline
131 | ) external payable returns (uint256[] memory amounts);
132 |
133 | function quote(
134 | uint256 amountA,
135 | uint256 reserveA,
136 | uint256 reserveB
137 | ) external pure returns (uint256 amountB);
138 |
139 | function getAmountOut(
140 | uint256 amountIn,
141 | uint256 reserveIn,
142 | uint256 reserveOut
143 | ) external pure returns (uint256 amountOut);
144 |
145 | function getAmountIn(
146 | uint256 amountOut,
147 | uint256 reserveIn,
148 | uint256 reserveOut
149 | ) external pure returns (uint256 amountIn);
150 |
151 | function getAmountsOut(uint256 amountIn, address[] calldata path)
152 | external
153 | view
154 | returns (uint256[] memory amounts);
155 |
156 | function getAmountsIn(uint256 amountOut, address[] calldata path)
157 | external
158 | view
159 | returns (uint256[] memory amounts);
160 | }
161 |
--------------------------------------------------------------------------------
/contracts/interface/IUniswapV2Router02.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | import "./IUniswapV2Router01.sol";
4 |
5 | contract IUniswapV2Router02 is IUniswapV2Router01 {
6 | function removeLiquidityETHSupportingFeeOnTransferTokens(
7 | address token,
8 | uint256 liquidity,
9 | uint256 amountTokenMin,
10 | uint256 amountETHMin,
11 | address to,
12 | uint256 deadline
13 | ) external returns (uint256 amountETH);
14 |
15 | function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
16 | address token,
17 | uint256 liquidity,
18 | uint256 amountTokenMin,
19 | uint256 amountETHMin,
20 | address to,
21 | uint256 deadline,
22 | bool approveMax,
23 | uint8 v,
24 | bytes32 r,
25 | bytes32 s
26 | ) external returns (uint256 amountETH);
27 |
28 | function swapExactTokensForTokensSupportingFeeOnTransferTokens(
29 | uint256 amountIn,
30 | uint256 amountOutMin,
31 | address[] calldata path,
32 | address to,
33 | uint256 deadline
34 | ) external;
35 |
36 | function swapExactETHForTokensSupportingFeeOnTransferTokens(
37 | uint256 amountOutMin,
38 | address[] calldata path,
39 | address to,
40 | uint256 deadline
41 | ) external payable;
42 |
43 | function swapExactTokensForETHSupportingFeeOnTransferTokens(
44 | uint256 amountIn,
45 | uint256 amountOutMin,
46 | address[] calldata path,
47 | address to,
48 | uint256 deadline
49 | ) external;
50 | }
51 |
--------------------------------------------------------------------------------
/contracts/interface/IVenus.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | interface IComptroller {
4 | function claimVenus(address[] calldata holders, address[] calldata vTokens, bool borrowers, bool suppliers) external;
5 | }
6 |
7 | interface IvToken {
8 | // uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
9 | function mint(uint256 mintAmount) external returns (uint256);
10 |
11 | // uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
12 | function redeemUnderlying(uint256 redeemAmount) external returns (uint256);
13 |
14 | function redeem(uint256 redeemTokens) external returns (uint256);
15 |
16 | // uint(Error.NO_ERROR), cTokenBalance, borrowBalance, exchangeRateMantissa
17 | function getAccountSnapshot(address account)
18 | external
19 | view
20 | returns (
21 | uint256,
22 | uint256,
23 | uint256,
24 | uint256
25 | );
26 |
27 | function balanceOfUnderlying(address owner) external returns (uint256);
28 |
29 | function getCash() external view returns (uint256);
30 |
31 | function comptroller() external view returns (IComptroller);
32 | }
33 |
--------------------------------------------------------------------------------
/contracts/library/DSAuth.sol:
--------------------------------------------------------------------------------
1 | // This program is free software: you can redistribute it and/or modify
2 | // it under the terms of the GNU General Public License as published by
3 | // the Free Software Foundation, either version 3 of the License, or
4 | // (at your option) any later version.
5 |
6 | // This program is distributed in the hope that it will be useful,
7 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | // GNU General Public License for more details.
10 |
11 | // You should have received a copy of the GNU General Public License
12 | // along with this program. If not, see .
13 |
14 | pragma solidity 0.5.12;
15 |
16 | contract DSAuthority {
17 | function canCall(
18 | address src,
19 | address dst,
20 | bytes4 sig
21 | ) public view returns (bool);
22 | }
23 |
24 | contract DSAuthEvents {
25 | event LogSetAuthority(address indexed authority);
26 | event LogSetOwner(address indexed owner);
27 | event OwnerUpdate(address indexed owner, address indexed newOwner);
28 | }
29 |
30 | contract DSAuth is DSAuthEvents {
31 | DSAuthority public authority;
32 | address public owner;
33 | address public newOwner;
34 |
35 | constructor() public {
36 | owner = msg.sender;
37 | emit LogSetOwner(msg.sender);
38 | }
39 |
40 | // Warning: you should absolutely sure you want to give up authority!!!
41 | function disableOwnership() public onlyOwner {
42 | owner = address(0);
43 | emit OwnerUpdate(msg.sender, owner);
44 | }
45 |
46 | function transferOwnership(address newOwner_) public onlyOwner {
47 | require(newOwner_ != owner, "TransferOwnership: the same owner.");
48 | newOwner = newOwner_;
49 | }
50 |
51 | function acceptOwnership() public {
52 | require(
53 | msg.sender == newOwner,
54 | "AcceptOwnership: only new owner do this."
55 | );
56 | emit OwnerUpdate(owner, newOwner);
57 | owner = newOwner;
58 | newOwner = address(0x0);
59 | }
60 |
61 | ///[snow] guard is Authority who inherit DSAuth.
62 | function setAuthority(DSAuthority authority_) public onlyOwner {
63 | authority = authority_;
64 | emit LogSetAuthority(address(authority));
65 | }
66 |
67 | modifier onlyOwner {
68 | require(isOwner(msg.sender), "ds-auth-non-owner");
69 | _;
70 | }
71 |
72 | function isOwner(address src) internal view returns (bool) {
73 | return bool(src == owner);
74 | }
75 |
76 | modifier auth {
77 | require(isAuthorized(msg.sender, msg.sig), "ds-auth-unauthorized");
78 | _;
79 | }
80 |
81 | function isAuthorized(address src, bytes4 sig)
82 | internal
83 | view
84 | returns (bool)
85 | {
86 | if (src == address(this)) {
87 | return true;
88 | } else if (src == owner) {
89 | return true;
90 | } else if (authority == DSAuthority(0)) {
91 | return false;
92 | } else {
93 | return authority.canCall(src, address(this), sig);
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/contracts/library/DSGuard.sol:
--------------------------------------------------------------------------------
1 | // guard.sol -- simple whitelist implementation of DSAuthority
2 |
3 | // Copyright (C) 2017 DappHub, LLC
4 |
5 | // This program is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 |
10 | // This program is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 |
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 |
18 | pragma solidity 0.5.12;
19 |
20 | import "./DSAuth.sol";
21 |
22 | contract DSGuardEvents {
23 | event LogPermit(
24 | bytes32 indexed src,
25 | bytes32 indexed dst,
26 | bytes32 indexed sig
27 | );
28 |
29 | event LogForbid(
30 | bytes32 indexed src,
31 | bytes32 indexed dst,
32 | bytes32 indexed sig
33 | );
34 | }
35 |
36 | contract DSGuard is DSAuth, DSAuthority, DSGuardEvents {
37 | bytes32 public constant ANY = bytes32(uint256(-1));
38 |
39 | mapping(bytes32 => mapping(bytes32 => mapping(bytes32 => bool))) acl;
40 |
41 | function canCall(
42 | address src_,
43 | address dst_,
44 | bytes4 sig
45 | ) public view returns (bool) {
46 | bytes32 src = bytes32(bytes20(src_));
47 | bytes32 dst = bytes32(bytes20(dst_));
48 |
49 | return
50 | acl[src][dst][sig] ||
51 | acl[src][dst][ANY] ||
52 | acl[src][ANY][sig] ||
53 | acl[src][ANY][ANY] ||
54 | acl[ANY][dst][sig] ||
55 | acl[ANY][dst][ANY] ||
56 | acl[ANY][ANY][sig] ||
57 | acl[ANY][ANY][ANY];
58 | }
59 |
60 | function permit(
61 | bytes32 src,
62 | bytes32 dst,
63 | bytes32 sig
64 | ) public auth {
65 | acl[src][dst][sig] = true;
66 | emit LogPermit(src, dst, sig);
67 | }
68 |
69 | function forbid(
70 | bytes32 src,
71 | bytes32 dst,
72 | bytes32 sig
73 | ) public auth {
74 | acl[src][dst][sig] = false;
75 | emit LogForbid(src, dst, sig);
76 | }
77 |
78 | function permit(
79 | address src,
80 | address dst,
81 | bytes32 sig
82 | ) public auth {
83 | permit(bytes32(bytes20(src)), bytes32(bytes20(dst)), sig);
84 | }
85 |
86 | function permitx(address src, address dst) public auth {
87 | permit(bytes32(bytes20(src)), bytes32(bytes20(dst)), ANY);
88 | }
89 |
90 | function forbid(
91 | address src,
92 | address dst,
93 | bytes32 sig
94 | ) public auth {
95 | forbid(bytes32(bytes20(src)), bytes32(bytes20(dst)), sig);
96 | }
97 |
98 | function forbidx(address src, address dst) public auth {
99 | forbid(bytes32(bytes20(src)), bytes32(bytes20(dst)), ANY);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/contracts/library/ERC20SafeTransfer.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | import "../interface/IERC20.sol";
4 |
5 | contract ERC20SafeTransfer {
6 | function doTransferOut(
7 | address _token,
8 | address _to,
9 | uint256 _amount
10 | ) internal returns (bool) {
11 | IERC20 token = IERC20(_token);
12 | bool result;
13 |
14 | token.transfer(_to, _amount);
15 |
16 | assembly {
17 | switch returndatasize()
18 | case 0 {
19 | result := not(0)
20 | }
21 | case 32 {
22 | returndatacopy(0, 0, 32)
23 | result := mload(0)
24 | }
25 | default {
26 | revert(0, 0)
27 | }
28 | }
29 | return result;
30 | }
31 |
32 | function doTransferFrom(
33 | address _token,
34 | address _from,
35 | address _to,
36 | uint256 _amount
37 | ) internal returns (bool) {
38 | IERC20 token = IERC20(_token);
39 | bool result;
40 |
41 | token.transferFrom(_from, _to, _amount);
42 |
43 | assembly {
44 | switch returndatasize()
45 | case 0 {
46 | result := not(0)
47 | }
48 | case 32 {
49 | returndatacopy(0, 0, 32)
50 | result := mload(0)
51 | }
52 | default {
53 | revert(0, 0)
54 | }
55 | }
56 | return result;
57 | }
58 |
59 | function doApprove(
60 | address _token,
61 | address _to,
62 | uint256 _amount
63 | ) internal returns (bool) {
64 | IERC20 token = IERC20(_token);
65 | bool result;
66 |
67 | token.approve(_to, _amount);
68 |
69 | assembly {
70 | switch returndatasize()
71 | case 0 {
72 | result := not(0)
73 | }
74 | case 32 {
75 | returndatacopy(0, 0, 32)
76 | result := mload(0)
77 | }
78 | default {
79 | revert(0, 0)
80 | }
81 | }
82 | return result;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/contracts/library/Pausable.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | import "./DSAuth.sol";
4 |
5 | /**
6 | * @dev Contract module which allows children to implement an emergency stop
7 | * mechanism that can be triggered by owner account.
8 | *
9 | * This module is used through inheritance. It will make available the
10 | * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
11 | * the functions of your contract. Note that they will not be pausable by
12 | * simply including this module, only once the modifiers are put in place.
13 | */
14 | contract Pausable is DSAuth {
15 | bool public paused;
16 |
17 | /**
18 | * @dev Emitted when the pause is triggered by a pauser (`account`).
19 | */
20 | event Paused(address account);
21 |
22 | /**
23 | * @dev Emitted when the pause is lifted by a pauser (`account`).
24 | */
25 | event Unpaused(address account);
26 |
27 | /**
28 | * @dev Modifier to make a function callable only when the contract is not paused.
29 | */
30 | modifier whenNotPaused() {
31 | require(!paused, "whenNotPaused: paused");
32 | _;
33 | }
34 |
35 | /**
36 | * @dev Modifier to make a function callable only when the contract is paused.
37 | */
38 | modifier whenPaused() {
39 | require(paused, "whenPaused: not paused");
40 | _;
41 | }
42 |
43 | /**
44 | * @dev Initializes the contract in unpaused state. Assigns the Pauser role
45 | * to the deployer.
46 | */
47 | constructor() internal {
48 | paused = false;
49 | }
50 |
51 | /**
52 | * @dev Called by the contract owner to pause, triggers stopped state.
53 | */
54 | function pause() public whenNotPaused auth {
55 | paused = true;
56 | emit Paused(owner);
57 | }
58 |
59 | /**
60 | * @dev Called by the contract owner to unpause, returns to normal state.
61 | */
62 | function unpause() public whenPaused auth {
63 | paused = false;
64 | emit Unpaused(owner);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/contracts/library/ReentrancyGuard.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | // SPDX-License-Identifier: MIT
4 |
5 | /**
6 | * @dev Contract module that helps prevent reentrant calls to a function.
7 | *
8 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
9 | * available, which can be applied to functions to make sure there are no nested
10 | * (reentrant) calls to them.
11 | *
12 | * Note that because there is a single `nonReentrant` guard, functions marked as
13 | * `nonReentrant` may not call one another. This can be worked around by making
14 | * those functions `private`, and then adding `external` `nonReentrant` entry
15 | * points to them.
16 | *
17 | * TIP: If you would like to learn more about reentrancy and alternative ways
18 | * to protect against it, check out our blog post
19 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
20 | */
21 | contract ReentrancyGuard {
22 | // Booleans are more expensive than uint256 or any type that takes up a full
23 | // word because each write operation emits an extra SLOAD to first read the
24 | // slot's contents, replace the bits taken up by the boolean, and then write
25 | // back. This is the compiler's defense against contract upgrades and
26 | // pointer aliasing, and it cannot be disabled.
27 |
28 | // The values being non-zero value makes deployment a bit more expensive,
29 | // but in exchange the refund on every call to nonReentrant will be lower in
30 | // amount. Since refunds are capped to a percentage of the total
31 | // transaction's gas, it is best to keep them low in cases like this one, to
32 | // increase the likelihood of the full refund coming into effect.
33 | uint256 private constant _NOT_ENTERED = 1;
34 | uint256 private constant _ENTERED = 2;
35 |
36 | uint256 private _status;
37 |
38 | constructor() internal {
39 | _status = _NOT_ENTERED;
40 | }
41 |
42 | /**
43 | * @dev Prevents a contract from calling itself, directly or indirectly.
44 | * Calling a `nonReentrant` function from another `nonReentrant`
45 | * function is not supported. It is possible to prevent this from happening
46 | * by making the `nonReentrant` function external, and make it call a
47 | * `private` function that does the actual work.
48 | */
49 | modifier nonReentrant() {
50 | // On the first call to nonReentrant, _notEntered will be true
51 | require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
52 |
53 | // Any calls to nonReentrant after this point will fail
54 | _status = _ENTERED;
55 |
56 | _;
57 |
58 | // By storing the original value once again, a refund is triggered (see
59 | // https://eips.ethereum.org/EIPS/eip-2200)
60 | _status = _NOT_ENTERED;
61 | }
62 |
63 | function initReentrancyStatus() internal {
64 | _status = _NOT_ENTERED;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/contracts/library/SafeMath.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | library SafeMath {
4 | function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
5 | require((z = x + y) >= x, "ds-math-add-overflow");
6 | }
7 |
8 | function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
9 | require((z = x - y) <= x, "ds-math-sub-underflow");
10 | }
11 |
12 | function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
13 | require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
14 | }
15 |
16 | function div(uint256 x, uint256 y) internal pure returns (uint256 z) {
17 | require(y > 0, "ds-math-div-overflow");
18 | z = x / y;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/contracts/mock/DispatcherMock.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | import "../library/SafeMath.sol";
4 |
5 | contract DispatcherMock {
6 | using SafeMath for uint256;
7 | /**
8 | * @dev List all handler contract address.
9 | */
10 | address[] public handlers;
11 |
12 | address public defaultHandler;
13 |
14 | /**
15 | * @dev Deposit ratio of each handler contract.
16 | * Notice: the sum of all deposit ratio should be 1000000.
17 | */
18 | mapping(address => uint256) public proportions;
19 |
20 | uint256 public constant totalProportion = 1000000;
21 |
22 | /**
23 | * @dev map: handlerAddress -> true/false,
24 | * Whether the handler has been added or not.
25 | */
26 | mapping(address => bool) public isHandlerActive;
27 |
28 | /**
29 | * @dev Set original handler contract and its depoist ratio.
30 | * Notice: the sum of all deposit ratio should be 1000000.
31 | * @param _handlers The original support handler contract.
32 | * @param _proportions The original depoist ratio of support handler.
33 | */
34 | constructor(address[] memory _handlers, uint256[] memory _proportions)
35 | public
36 | {
37 | setHandlers(_handlers, _proportions);
38 | }
39 |
40 | /**
41 | * @dev Replace current handlers with _handlers and corresponding _proportions,
42 | * @param _handlers The list of new handlers, the 1st one will act as default hanlder.
43 | * @param _proportions The list of corresponding proportions.
44 | */
45 | function setHandlers(
46 | address[] memory _handlers,
47 | uint256[] memory _proportions
48 | ) private {
49 | require(
50 | _handlers.length == _proportions.length && _handlers.length > 0,
51 | "setHandlers: handlers & proportions should not have 0 or different lengths"
52 | );
53 |
54 | uint256 _sum = 0;
55 | for (uint256 i = 0; i < _handlers.length; i++) {
56 | require(
57 | _handlers[i] != address(0),
58 | "setHandlers: handlerAddr contract address invalid"
59 | );
60 |
61 | _sum = _sum.add(_proportions[i]);
62 |
63 | handlers.push(_handlers[i]);
64 | proportions[_handlers[i]] = _proportions[i];
65 | isHandlerActive[_handlers[i]] = true;
66 | }
67 |
68 | // The sum of proportions should be 1000000.
69 | require(
70 | _sum == totalProportion,
71 | "the sum of proportions must be 1000000"
72 | );
73 | }
74 |
75 | function setDefaultHandler(address _defaultHandler) public {
76 | defaultHandler = _defaultHandler;
77 | }
78 |
79 | function activeDefaultHandler() public {
80 | isHandlerActive[defaultHandler] = true;
81 | }
82 |
83 | function getHandlers()
84 | external
85 | view
86 | returns (address[] memory, uint256[] memory)
87 | {
88 | address[] memory _handlers = handlers;
89 | uint256[] memory _proportions = new uint256[](_handlers.length);
90 | for (uint256 i = 0; i < _proportions.length; i++)
91 | _proportions[i] = proportions[_handlers[i]];
92 |
93 | return (_handlers, _proportions);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/contracts/mock/TestERC20.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | import "../library/SafeMath.sol";
4 |
5 | contract TestERC20 {
6 | using SafeMath for uint256;
7 | // --- Data ---
8 | // --- ERC20 Data ---
9 | string public name;
10 | string public symbol;
11 | uint8 public decimals;
12 | uint256 public totalSupply;
13 |
14 | mapping(address => uint256) public balanceOf;
15 | mapping(address => mapping(address => uint256)) public allowance;
16 |
17 | uint256 constant BASE = 10**18;
18 | uint256 public fee;
19 | address public feeRecipient;
20 | // --- Event ---
21 | event Approval(address indexed src, address indexed guy, uint256 wad);
22 | event Transfer(address indexed src, address indexed dst, uint256 wad);
23 |
24 | /**
25 | * The constructor is used here to ensure that the implementation
26 | * contract is initialized. An uncontrolled implementation
27 | * contract might lead to misleading state
28 | * for users who accidentally interact with it.
29 | */
30 | constructor(
31 | string memory _name,
32 | string memory _symbol,
33 | uint8 _decimals
34 | ) public {
35 | name = _name;
36 | symbol = _symbol;
37 | decimals = _decimals;
38 | feeRecipient = msg.sender;
39 | }
40 |
41 | function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
42 | z = x.mul(y) / BASE;
43 | }
44 |
45 | function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
46 | z = x.mul(BASE).div(y);
47 | }
48 |
49 | function rdivup(uint256 x, uint256 y) internal pure returns (uint256 z) {
50 | z = x.mul(BASE).add(y.sub(1)).div(y);
51 | }
52 |
53 | function updateFee(uint256 _fee) external {
54 | require(_fee <= BASE, "updateFee: incorrect fee.");
55 | fee = _fee;
56 | }
57 |
58 | // --- Token ---
59 | function transfer(address _dst, uint256 _wad) external returns (bool) {
60 | return transferFrom(msg.sender, _dst, _wad);
61 | }
62 |
63 | function transferFrom(
64 | address _src,
65 | address _dst,
66 | uint256 _wad
67 | ) public returns (bool) {
68 | if (balanceOf[_src] < _wad) return false;
69 |
70 | if (_src != msg.sender && allowance[_src][msg.sender] != uint256(-1)) {
71 | require(
72 | allowance[_src][msg.sender] >= _wad,
73 | "transferFrom: insufficient allowance"
74 | );
75 | allowance[_src][msg.sender] = allowance[_src][msg.sender].sub(_wad);
76 | }
77 |
78 | balanceOf[_src] = balanceOf[_src].sub(_wad);
79 | uint256 _fee = rmul(_wad, fee);
80 | if (_fee > 0) {
81 | balanceOf[feeRecipient] = balanceOf[feeRecipient].add(_fee);
82 | emit Transfer(_src, feeRecipient, _fee);
83 | }
84 |
85 | balanceOf[_dst] = balanceOf[_dst].add(_wad.sub(_fee));
86 | emit Transfer(_src, _dst, _wad.sub(_fee));
87 | return true;
88 | }
89 |
90 | function approve(address _spender, uint256 _wad) external returns (bool) {
91 | if (allowance[msg.sender][_spender] > 0) return false;
92 | allowance[msg.sender][_spender] = _wad;
93 | emit Approval(msg.sender, _spender, _wad);
94 | return true;
95 | }
96 |
97 | function allocateTo(address _spender, uint256 _wad) external {
98 | balanceOf[_spender] = balanceOf[_spender].add(_wad);
99 | totalSupply = totalSupply.add(_wad);
100 | emit Transfer(address(0), _spender, _wad);
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/contracts/mock/TestHandlerMock.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.5.12;
2 |
3 | import "../interface/IHandler.sol";
4 |
5 | contract TestHandlerMock {
6 | uint256 public returnValue;
7 |
8 | constructor() public {}
9 |
10 | function getRealBalance(address _handlder, address _underlyingToken)
11 | external
12 | {
13 | returnValue = IHandler(_handlder).getBalance(_underlyingToken);
14 | }
15 |
16 | function getRealLiquidity(address _handlder, address _underlyingToken)
17 | external
18 | {
19 | returnValue = IHandler(_handlder).getLiquidity(_underlyingToken);
20 | }
21 |
22 | function deposit(
23 | address _handlder,
24 | address _underlyingToken,
25 | uint256 _amount
26 | ) external {
27 | returnValue = IHandler(_handlder).deposit(_underlyingToken, _amount);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/migrations/3_deploy_dForce_implementation.js:
--------------------------------------------------------------------------------
1 | // Right click on the script name and hit "Run" to execute
2 | (async () => {
3 | try {
4 | console.log("Running deployWithEthers script...");
5 |
6 | const contractName = "DForceLendingHandler"; // Change this for other contract
7 |
8 | // Note that the script needs the ABI which is generated from the compilation artifact.
9 | // Make sure contract is compiled and artifacts are generated
10 | const artifactsPath = `browser/build/contracts/${contractName}.json`; // Change this for different path
11 | const dTokenController = "0x7F15bf6D40bfEE79099bCcA893a30B72Aee6C9Eb";
12 | const rewardToken = "0x4A9A2b2b04549C3927dd2c9668A5eF3fCA473623";
13 |
14 | const constructorArgs = [dTokenController, rewardToken];
15 |
16 | const metadata = JSON.parse(
17 | await remix.call("fileManager", "getFile", artifactsPath)
18 | );
19 |
20 | // 'web3Provider' is a remix global variable object
21 | const signer = new ethers.providers.Web3Provider(web3Provider).getSigner();
22 |
23 | let factory = new ethers.ContractFactory(
24 | metadata.abi,
25 | metadata.bytecode,
26 | signer
27 | );
28 |
29 | let contract = await factory.deploy(...constructorArgs);
30 |
31 | console.log("Contract Address: ", contract.address);
32 |
33 | // The contract is NOT deployed yet; we must wait until it is mined
34 | await contract.deployed();
35 | console.log("Deployment successful.");
36 | } catch (e) {
37 | console.log(e.message);
38 | }
39 | })();
40 |
--------------------------------------------------------------------------------
/migrations/4_deploy_dforce_handler_proxy.js:
--------------------------------------------------------------------------------
1 |
2 | // Right click on the script name and hit "Run" to execute
3 | (async () => {
4 | try {
5 | console.log("Running deployWithEthers script...");
6 |
7 | const contractName = "DTokenProxy"; // Change this for other contract
8 |
9 | // Note that the script needs the ABI which is generated from the compilation artifact.
10 | // Make sure contract is compiled and artifacts are generated
11 | const artifactsPath = `browser/build/contracts/${contractName}.json`; // Change this for different path
12 | const dforce_handler_implementation = "0xBAdAe913fA64F8c11040b334BD2bEbfbE14F8e17";
13 |
14 | const constructorArgs = [dforce_handler_implementation];
15 |
16 | const metadata = JSON.parse(
17 | await remix.call("fileManager", "getFile", artifactsPath)
18 | );
19 |
20 | // 'web3Provider' is a remix global variable object
21 | const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner();
22 |
23 | let factory = new ethers.ContractFactory(
24 | metadata.abi,
25 | metadata.bytecode,
26 | signer
27 | );
28 |
29 | let contract = await factory.deploy(...constructorArgs);
30 |
31 | console.log("Contract Address: ", contract.address);
32 |
33 | // The contract is NOT deployed yet; we must wait until it is mined
34 | await contract.deployed();
35 | console.log("Deployment successful.");
36 | } catch (e) {
37 | console.log(e.message);
38 | }
39 | })();
40 |
--------------------------------------------------------------------------------
/migrations/5_config_for_dforce_handler.js:
--------------------------------------------------------------------------------
1 |
2 | // Right click on the script name and hit "Run" to execute
3 | (async () => {
4 | try {
5 | console.log("Running deployWithEthers script...");
6 |
7 | const contractName = "DForceLendingHandler"; // Change this for other contract
8 |
9 | // Note that the script needs the ABI which is generated from the compilation artifact.
10 | // Make sure contract is compiled and artifacts are generated
11 | const artifactsPath = `browser/build/contracts/${contractName}.json`; // Change this for different path
12 | const dTokenController = "0x7F15bf6D40bfEE79099bCcA893a30B72Aee6C9Eb";
13 | const rewardToken = "0x4A9A2b2b04549C3927dd2c9668A5eF3fCA473623";
14 | let dsGurad = "0x5C4365BE7a01c6f0B8709D3b619ffD26eE072bDC";
15 | const dforce_handler_proxy_addr = "0xc9b972fd675A0f7888dC143a2c0B32193C9B02FF";
16 |
17 | let dai = "0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3";
18 | let idai = "0xAD5Ec11426970c32dA48f58c92b1039bC50e5492";
19 |
20 | // const constructorArgs = [busd_handler];
21 |
22 | const metadata = JSON.parse(
23 | await remix.call("fileManager", "getFile", artifactsPath)
24 | );
25 |
26 | // 'web3Provider' is a remix global variable object
27 | const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner();
28 |
29 | let factory = new ethers.ContractFactory(
30 | metadata.abi,
31 | metadata.bytecode,
32 | signer
33 | );
34 |
35 | const handler_proxy = new ethers.Contract(dforce_handler_proxy_addr, metadata.abi, signer);
36 |
37 | //-------------------------------
38 | //---- initialize contract ------
39 | //-------------------------------
40 | let current_reward_token = await handler_proxy.rewardToken();
41 | console.log("reward doken is: ", current_reward_token);
42 |
43 | let tx = await handler_proxy.initialize(dTokenController, rewardToken);
44 | await tx.wait(1);
45 |
46 | current_reward_token = await handler_proxy.rewardToken();
47 | console.log("reward doken is: ", current_reward_token);
48 |
49 | //-------------------------
50 | //---- enable tokens ------
51 | //-------------------------
52 | let token_has_been_enabled = await handler_proxy.tokenIsEnabled(dai);
53 | console.log("token has been enabled:", token_has_been_enabled);
54 |
55 | tx = await handler_proxy.enableTokens([dai]);
56 | await tx.wait(1);
57 |
58 | token_has_been_enabled = await handler_proxy.tokenIsEnabled(dai);
59 | console.log("token has been enabled:", token_has_been_enabled);
60 |
61 | //-------------------------
62 | //---- set authority ------
63 | //-------------------------
64 | let current_authority = await handler_proxy.authority();
65 | console.log("current authority is: ", current_authority);
66 | tx = await handler_proxy.setAuthority(dsGurad);
67 | await tx.wait(1);
68 |
69 | current_authority = await handler_proxy.authority();
70 | console.log("current authority is: ", current_authority);
71 |
72 | //------------------------------
73 | //----set iTokens relation------
74 | //------------------------------
75 | let iTokens_relation = await handler_proxy.iTokens(dai);
76 | console.log("iTokens relation is: ", iTokens_relation);
77 |
78 | tx = await handler_proxy.setiTokensRelation([dai],[idai]);
79 | await tx.wait(1);
80 |
81 | iTokens_relation = await handler_proxy.iTokens(dai);
82 | console.log("iTokens relation is: ", iTokens_relation);
83 | } catch (e) {
84 | console.log(e.message);
85 | }
86 | })();
87 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dtoken",
3 | "version": "0.1.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "npx buidler test",
8 | "copy-uniswap-artifacts": "cp node_modules/@uniswap/v2-core/build/*.json artifacts/ && cp node_modules/@uniswap/v2-periphery/build/*.json artifacts/",
9 | "format": "prettier --write contracts test --ignore-path .prettierignore"
10 | },
11 | "author": "",
12 | "license": "MIT",
13 | "devDependencies": {
14 | "@nomiclabs/buidler": "^1.3.5",
15 | "@nomiclabs/buidler-ethers": "^2.0.0",
16 | "@nomiclabs/buidler-truffle5": "^1.3.4",
17 | "@nomiclabs/buidler-waffle": "^2.0.0",
18 | "@nomiclabs/buidler-web3": "^1.3.4",
19 | "@uniswap/v2-core": "^1.0.1",
20 | "@uniswap/v2-periphery": "^1.1.0-beta.0",
21 | "buidler-gas-reporter": "^0.1.3",
22 | "dotenv": "^8.2.0",
23 | "ethereum-doppelganger": "0.0.7",
24 | "ethereum-waffle": "^3.0.0",
25 | "ethers": "^5.0.3",
26 | "prettier": "^2.0.5",
27 | "prettier-plugin-solidity": "^1.0.0-alpha.53",
28 | "solidity-coverage": "^0.7.9",
29 | "solidity-docgen": "^0.5.3",
30 | "truffle-assertions": "^0.9.2",
31 | "truffle-hdwallet-provider": "^1.0.17",
32 | "web3": "^1.2.8"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/test/testAaveHandler.js:
--------------------------------------------------------------------------------
1 | const FiatToken = artifacts.require("FiatTokenV1");
2 | const LendingPoolCore = artifacts.require("AaveLendingPoolCoreMock");
3 | const LendPool = artifacts.require("AaveLendPoolMock");
4 | const aTokenMock = artifacts.require("aTokenMock");
5 | const AaveHandler = artifacts.require("AaveHandler");
6 | const DTokenController = artifacts.require("DTokenController");
7 | const Dispatcher = artifacts.require("Dispatcher");
8 | const DToken = artifacts.require("DToken");
9 |
10 | const BN = require("bn.js");
11 | const UINT256_MAX = new BN(2).pow(new BN(256)).sub(new BN(1));
12 |
13 | describe("Aave handler contract", function () {
14 | let accounts;
15 | let usdc;
16 | let aUSDC, dUSDC, dispatcher;
17 | let lendingPoolCore;
18 | let lendingPool;
19 | let aaveHandler;
20 | let dTokenController;
21 |
22 | before(async function () {
23 | // Gets accounts
24 | accounts = await web3.eth.getAccounts();
25 |
26 | // Deploys underlying assets
27 | usdc = await FiatToken.new(
28 | "USDC", // _name
29 | "USDC", // _symbol
30 | "USD", // _currency
31 | 6, // _decimals
32 | accounts[0], // _masterMinter
33 | accounts[1], // _pauser
34 | accounts[0] // _blacklister
35 | );
36 |
37 | // Deploys dToken mapping contract
38 | dTokenController = await DTokenController.new();
39 |
40 | // Deploys Aave system
41 | lendingPoolCore = await LendingPoolCore.new();
42 | aUSDC = await aTokenMock.new(
43 | "aUSDC",
44 | "aUSDC",
45 | usdc.address,
46 | lendingPoolCore.address
47 | );
48 | await lendingPoolCore.setReserveATokenAddress(usdc.address, aUSDC.address);
49 | lendingPool = await LendPool.new(lendingPoolCore.address);
50 | aaveHandler = await AaveHandler.new(
51 | dTokenController.address,
52 | lendingPool.address,
53 | lendingPoolCore.address
54 | );
55 |
56 | dispatcher = await Dispatcher.new([aaveHandler.address], [1000000]);
57 | dUSDC = await DToken.new(
58 | "dUSDC",
59 | "dUSDC",
60 | usdc.address,
61 | dispatcher.address
62 | );
63 |
64 | // Faucets assets:
65 | console.log(
66 | "Before faucet, usdc balance: ",
67 | (await usdc.balanceOf(accounts[0])).toString()
68 | );
69 | await usdc.allocateTo(accounts[0], 1000e6);
70 | await usdc.allocateTo(aUSDC.address, 10000e6);
71 | console.log(
72 | "After faucet, usdc balance: ",
73 | (await usdc.balanceOf(accounts[0])).toString()
74 | );
75 | });
76 |
77 | describe("Deployment", function () {
78 | it("Deploy aave handler contract", async function () {
79 | console.log(
80 | "before enable usdc, aave handler supports it: ",
81 | await aaveHandler.tokenIsEnabled(usdc.address)
82 | );
83 | await aaveHandler.enableTokens([usdc.address]);
84 | console.log(
85 | "after enable usdc, aave handler supports it: ",
86 | await aaveHandler.tokenIsEnabled(usdc.address)
87 | );
88 |
89 | await dTokenController.setdTokensRelation(
90 | [usdc.address],
91 | [dUSDC.address]
92 | );
93 |
94 | await aaveHandler.approve(usdc.address, UINT256_MAX);
95 |
96 | await usdc.allocateTo(aaveHandler.address, 1000e6);
97 | console.log(
98 | "before deposit, aave handler usdc balance is: ",
99 | (await usdc.balanceOf(aaveHandler.address)).toString()
100 | );
101 | console.log(
102 | "before deposit, aave handler aUSDC balance is: ",
103 | (await aUSDC.balanceOf(aaveHandler.address)).toString()
104 | );
105 |
106 | await aaveHandler.deposit(usdc.address, 100);
107 |
108 | console.log(
109 | "after deposit, aave handler usdc balance is: ",
110 | (await usdc.balanceOf(aaveHandler.address)).toString()
111 | );
112 | console.log(
113 | "after deposit, aave handler aUSDC balance is: ",
114 | (await aUSDC.balanceOf(aaveHandler.address)).toString()
115 | );
116 |
117 | console.log(
118 | "before withdraw, aave handler usdc balance is: ",
119 | (await usdc.balanceOf(aaveHandler.address)).toString()
120 | );
121 | console.log(
122 | "before withdraw, aave handler aUSDC balance is: ",
123 | (await aUSDC.balanceOf(aaveHandler.address)).toString()
124 | );
125 | await aaveHandler.withdraw(usdc.address, 10);
126 | console.log(
127 | "after withdraw, aave handler usdc balance is: ",
128 | (await usdc.balanceOf(aaveHandler.address)).toString()
129 | );
130 | console.log(
131 | "after withdraw, aave handler aUSDC balance is: ",
132 | (await aUSDC.balanceOf(aaveHandler.address)).toString()
133 | );
134 | });
135 | });
136 | });
137 |
--------------------------------------------------------------------------------
/test/testDTokenController.js:
--------------------------------------------------------------------------------
1 | const truffleAssert = require("truffle-assertions");
2 | const DTokenController = artifacts.require("DTokenController");
3 |
4 | const MOCK_TOKEN = "0x0000000000000000000000000000000000000001";
5 | const MOCK_DTOKEN = "0x0000000000000000000000000000000000000002";
6 | const MOCK_DTOKEN_NEW = "0x0000000000000000000000000000000000000003";
7 | const UNKNOWN_TOKEN = "0x0000000000000000000000000000000000000004";
8 |
9 | describe("DTokenController Contract", function () {
10 | let dtoken_controller;
11 | let owner, account1, account2, account3, account4;
12 |
13 | before(async function () {
14 | [
15 | owner,
16 | account1,
17 | account2,
18 | account3,
19 | account4,
20 | ] = await web3.eth.getAccounts();
21 | });
22 |
23 | async function resetContracts(handler_num, proportions) {
24 | dtoken_controller = await DTokenController.new();
25 | }
26 |
27 | describe("Deployment", function () {
28 | it("Should deployed and only initialized once", async function () {
29 | await resetContracts();
30 |
31 | await truffleAssert.reverts(
32 | dtoken_controller.initialize(),
33 | "initialize: Already initialized!"
34 | );
35 | });
36 | });
37 |
38 | describe("setdTokensRelation", function () {
39 | it("Should allow only owner to set dTokenController relation", async function () {
40 | let tokens = [MOCK_TOKEN];
41 | let dTokenController = [MOCK_DTOKEN];
42 | await dtoken_controller.setdTokensRelation(tokens, dTokenController);
43 |
44 | await truffleAssert.reverts(
45 | dtoken_controller.setdTokensRelation(tokens, dTokenController, {
46 | from: account1,
47 | }),
48 | "ds-auth-unauthorized"
49 | );
50 | });
51 |
52 | it("Should not set dTokenController relation with mismatched length mappings", async function () {
53 | let tokens = [MOCK_TOKEN];
54 | let dTokenController = [];
55 |
56 | await truffleAssert.reverts(
57 | dtoken_controller.setdTokensRelation(tokens, dTokenController),
58 | "setdTokensRelation: Array length do not match!"
59 | );
60 | });
61 |
62 | it("Should not set dTokenController relation which has been set", async function () {
63 | let tokens = [MOCK_TOKEN];
64 | let dTokenController = [MOCK_DTOKEN];
65 |
66 | await truffleAssert.reverts(
67 | dtoken_controller.setdTokensRelation(tokens, dTokenController),
68 | "_setdTokenRelation: Has set!"
69 | );
70 | });
71 | });
72 |
73 | describe("updatedTokenRelation", function () {
74 | it("Should allow only owner to update dTokenController relation", async function () {
75 | await dtoken_controller.updatedTokenRelation(MOCK_TOKEN, MOCK_DTOKEN_NEW);
76 |
77 | await truffleAssert.reverts(
78 | dtoken_controller.updatedTokenRelation(MOCK_TOKEN, MOCK_DTOKEN_NEW, {
79 | from: account1,
80 | }),
81 | "ds-auth-unauthorized"
82 | );
83 | });
84 |
85 | it("Should not update dTokenController relation with unknown token", async function () {
86 | await truffleAssert.reverts(
87 | dtoken_controller.updatedTokenRelation(UNKNOWN_TOKEN, MOCK_DTOKEN),
88 | "updatedTokenRelation: token does not exist!"
89 | );
90 | });
91 | });
92 |
93 | describe("getdToken", function () {
94 | it("Should get dTokenController relation and 0 by default", async function () {
95 | assert.equal(
96 | MOCK_DTOKEN_NEW,
97 | await dtoken_controller.getDToken(MOCK_TOKEN)
98 | );
99 | assert.equal(0, await dtoken_controller.getDToken(UNKNOWN_TOKEN));
100 | });
101 | });
102 | });
103 |
--------------------------------------------------------------------------------
/truffle-config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Use this file to configure your truffle project. It's seeded with some
3 | * common settings for different networks and features like migrations,
4 | * compilation and testing. Uncomment the ones you need or modify
5 | * them to suit your project as necessary.
6 | *
7 | * More information about configuration can be found at:
8 | *
9 | * truffleframework.com/docs/advanced/configuration
10 | *
11 | * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
12 | * to sign your transactions before they're sent to a remote public node. Infura API
13 | * keys are available for free at: infura.io/register
14 | *
15 | * > > Using Truffle V5 or later? Make sure you install the `web3-one` version.
16 | *
17 | * > > $ npm install truffle-hdwallet-provider@web3-one
18 | *
19 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
20 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this
21 | * phrase from a file you've .gitignored so it doesn't accidentally become public.
22 | *
23 | */
24 |
25 | require('dotenv').config();
26 |
27 | const HDWalletProvider = require("truffle-hdwallet-provider");
28 | var infuraKey = process.env.INFURA_APIKEY;
29 | var privateKeys = JSON.parse(process.env.PRIVATE_KEYS);
30 | const keyLength = privateKeys.length;
31 |
32 |
33 | module.exports = {
34 | /**
35 | * Networks define how you connect to your ethereum client and let you set the
36 | * defaults web3 uses to send transactions. If you don't specify one truffle
37 | * will spin up a development blockchain for you on port 9545 when you
38 | * run `develop` or `test`. You can ask a truffle command to use a specific
39 | * network from the command line, e.g
40 | *
41 | * $ truffle test --network
42 | */
43 |
44 | networks: {
45 | // Useful for testing. The `development` name is special - truffle uses it by default
46 | // if it's defined here and no other network is specified at the command line.
47 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal
48 | // tab if you use this network and you must also set the `host`, `port` and `network_id`
49 | // options below to some value.
50 | //
51 | development: {
52 | host: "localhost",
53 | port: 7545,
54 | network_id: "*",
55 | gasPrice: 20000000000,
56 | gas: 8000000
57 | },
58 |
59 | mainnet: {
60 | provider: () => new HDWalletProvider(privateKeys, `https://mainnet.infura.io/v3/${infuraKey}`, 0 , keyLength),
61 | network_id: 1, // Mainnet's id
62 | gas: 6721975, // Gas limit used for deploys
63 | gasPrice: 7000000000, // Gas price used for deploys: 7gwei
64 | confirmations: 2,
65 | timeoutBlocks: 200,
66 | skipDryRun: true
67 | },
68 |
69 | kovan: {
70 | provider: () => new HDWalletProvider(privateKeys, `https://kovan.infura.io/v3/${infuraKey}`, 0 , keyLength),
71 | network_id: 42, // Kovan's id
72 | gas: 6721975,
73 | gasPrice: 10000000000, // Gas price used for deploys: 10gwei
74 | confirmations: 2,
75 | timeoutBlocks: 200,
76 | skipDryRun: true,
77 | networkCheckTimeout: 600000
78 | },
79 |
80 | ropsten: {
81 | provider: () => new HDWalletProvider(privateKeys, `https://ropsten.infura.io/v3/${infuraKey}`, 0 , keyLength),
82 | network_id: 3, // ropsten's id
83 | gas: 6721975,
84 | gasPrice: 10000000000, // Gas price used for deploys: 10gwei
85 | confirmations: 2,
86 | timeoutBlocks: 200,
87 | skipDryRun: true
88 | },
89 |
90 | rinkeby: {
91 | provider: () => new HDWalletProvider(privateKeys, `https://rinkeby.infura.io/v3/${infuraKey}`, 0 , keyLength),
92 | network_id: 4, // ropsten's id
93 | gas: 6721975,
94 | gasPrice: 10000000000, // Gas price used for deploys: 10gwei
95 | confirmations: 2,
96 | timeoutBlocks: 200,
97 | skipDryRun: true
98 | }
99 | },
100 |
101 | // Set default mocha options here, use special reporters etc.
102 | mocha: {
103 | enableTimeouts: false,
104 | useColors: true,
105 | bail: true
106 | },
107 |
108 | // Configure your compilers
109 | compilers: {
110 | solc: {
111 | version: "0.5.12", // Fetch exact version from solc-bin (default: truffle's version)
112 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
113 | settings: { // See the solidity docs for advice about optimization and evmVersion
114 | optimizer: {
115 | enabled: true,
116 | runs: 200
117 | },
118 | // evmVersion: "byzantium"
119 | // }
120 | }
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/web-dapp/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | node_modules
3 | # testing
4 | /coverage
--------------------------------------------------------------------------------
/web-dapp/build.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dforce-network/dToken/05bda1f755becb7e3706c648aca0af57b69b9822/web-dapp/build.zip
--------------------------------------------------------------------------------
/web-dapp/config/env.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const paths = require('./paths');
6 |
7 | // Make sure that including paths.js after env.js will read .env variables.
8 | delete require.cache[require.resolve('./paths')];
9 |
10 | const NODE_ENV = process.env.NODE_ENV;
11 | if (!NODE_ENV) {
12 | throw new Error(
13 | 'The NODE_ENV environment variable is required but was not specified.'
14 | );
15 | }
16 |
17 | // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
18 | const dotenvFiles = [
19 | `${paths.dotenv}.${NODE_ENV}.local`,
20 | `${paths.dotenv}.${NODE_ENV}`,
21 | // Don't include `.env.local` for `test` environment
22 | // since normally you expect tests to produce the same
23 | // results for everyone
24 | NODE_ENV !== 'test' && `${paths.dotenv}.local`,
25 | paths.dotenv,
26 | ].filter(Boolean);
27 |
28 | // Load environment variables from .env* files. Suppress warnings using silent
29 | // if this file is missing. dotenv will never modify any environment variables
30 | // that have already been set. Variable expansion is supported in .env files.
31 | // https://github.com/motdotla/dotenv
32 | // https://github.com/motdotla/dotenv-expand
33 | dotenvFiles.forEach(dotenvFile => {
34 | if (fs.existsSync(dotenvFile)) {
35 | require('dotenv-expand')(
36 | require('dotenv').config({
37 | path: dotenvFile,
38 | })
39 | );
40 | }
41 | });
42 |
43 | // We support resolving modules according to `NODE_PATH`.
44 | // This lets you use absolute paths in imports inside large monorepos:
45 | // https://github.com/facebook/create-react-app/issues/253.
46 | // It works similar to `NODE_PATH` in Node itself:
47 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
48 | // Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
49 | // Otherwise, we risk importing Node.js core modules into an app instead of webpack shims.
50 | // https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
51 | // We also resolve them to make sure all tools using them work consistently.
52 | const appDirectory = fs.realpathSync(process.cwd());
53 | process.env.NODE_PATH = (process.env.NODE_PATH || '')
54 | .split(path.delimiter)
55 | .filter(folder => folder && !path.isAbsolute(folder))
56 | .map(folder => path.resolve(appDirectory, folder))
57 | .join(path.delimiter);
58 |
59 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
60 | // injected into the application via DefinePlugin in webpack configuration.
61 | const REACT_APP = /^REACT_APP_/i;
62 |
63 | function getClientEnvironment(publicUrl) {
64 | const raw = Object.keys(process.env)
65 | .filter(key => REACT_APP.test(key))
66 | .reduce(
67 | (env, key) => {
68 | env[key] = process.env[key];
69 | return env;
70 | },
71 | {
72 | // Useful for determining whether we’re running in production mode.
73 | // Most importantly, it switches React into the correct mode.
74 | NODE_ENV: process.env.NODE_ENV || 'development',
75 | // Useful for resolving the correct path to static assets in `public`.
76 | // For example,
.
77 | // This should only be used as an escape hatch. Normally you would put
78 | // images into the `src` and `import` them in code to get their paths.
79 | PUBLIC_URL: publicUrl,
80 | // We support configuring the sockjs pathname during development.
81 | // These settings let a developer run multiple simultaneous projects.
82 | // They are used as the connection `hostname`, `pathname` and `port`
83 | // in webpackHotDevClient. They are used as the `sockHost`, `sockPath`
84 | // and `sockPort` options in webpack-dev-server.
85 | WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
86 | WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
87 | WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
88 | }
89 | );
90 | // Stringify all values so we can feed into webpack DefinePlugin
91 | const stringified = {
92 | 'process.env': Object.keys(raw).reduce((env, key) => {
93 | env[key] = JSON.stringify(raw[key]);
94 | return env;
95 | }, {}),
96 | };
97 |
98 | return { raw, stringified };
99 | }
100 |
101 | module.exports = getClientEnvironment;
102 |
--------------------------------------------------------------------------------
/web-dapp/config/getHttpsConfig.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const crypto = require('crypto');
6 | const chalk = require('react-dev-utils/chalk');
7 | const paths = require('./paths');
8 |
9 | // Ensure the certificate and key provided are valid and if not
10 | // throw an easy to debug error
11 | function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
12 | let encrypted;
13 | try {
14 | // publicEncrypt will throw an error with an invalid cert
15 | encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
16 | } catch (err) {
17 | throw new Error(
18 | `The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
19 | );
20 | }
21 |
22 | try {
23 | // privateDecrypt will throw an error with an invalid key
24 | crypto.privateDecrypt(key, encrypted);
25 | } catch (err) {
26 | throw new Error(
27 | `The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
28 | err.message
29 | }`
30 | );
31 | }
32 | }
33 |
34 | // Read file and throw an error if it doesn't exist
35 | function readEnvFile(file, type) {
36 | if (!fs.existsSync(file)) {
37 | throw new Error(
38 | `You specified ${chalk.cyan(
39 | type
40 | )} in your env, but the file "${chalk.yellow(file)}" can't be found.`
41 | );
42 | }
43 | return fs.readFileSync(file);
44 | }
45 |
46 | // Get the https config
47 | // Return cert files if provided in env, otherwise just true or false
48 | function getHttpsConfig() {
49 | const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
50 | const isHttps = HTTPS === 'true';
51 |
52 | if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
53 | const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
54 | const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
55 | const config = {
56 | cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
57 | key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
58 | };
59 |
60 | validateKeyAndCerts({ ...config, keyFile, crtFile });
61 | return config;
62 | }
63 | return isHttps;
64 | }
65 |
66 | module.exports = getHttpsConfig;
67 |
--------------------------------------------------------------------------------
/web-dapp/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/en/webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return 'module.exports = {};';
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return 'cssTransform';
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/web-dapp/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const camelcase = require('camelcase');
5 |
6 | // This is a custom Jest transformer turning file imports into filenames.
7 | // http://facebook.github.io/jest/docs/en/webpack.html
8 |
9 | module.exports = {
10 | process(src, filename) {
11 | const assetFilename = JSON.stringify(path.basename(filename));
12 |
13 | if (filename.match(/\.svg$/)) {
14 | // Based on how SVGR generates a component name:
15 | // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
16 | const pascalCaseFilename = camelcase(path.parse(filename).name, {
17 | pascalCase: true,
18 | });
19 | const componentName = `Svg${pascalCaseFilename}`;
20 | return `const React = require('react');
21 | module.exports = {
22 | __esModule: true,
23 | default: ${assetFilename},
24 | ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
25 | return {
26 | $$typeof: Symbol.for('react.element'),
27 | type: 'svg',
28 | ref: ref,
29 | key: null,
30 | props: Object.assign({}, props, {
31 | children: ${assetFilename}
32 | })
33 | };
34 | }),
35 | };`;
36 | }
37 |
38 | return `module.exports = ${assetFilename};`;
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/web-dapp/config/modules.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const paths = require('./paths');
6 | const chalk = require('react-dev-utils/chalk');
7 | const resolve = require('resolve');
8 |
9 | /**
10 | * Get additional module paths based on the baseUrl of a compilerOptions object.
11 | *
12 | * @param {Object} options
13 | */
14 | function getAdditionalModulePaths(options = {}) {
15 | const baseUrl = options.baseUrl;
16 |
17 | // We need to explicitly check for null and undefined (and not a falsy value) because
18 | // TypeScript treats an empty string as `.`.
19 | if (baseUrl == null) {
20 | // If there's no baseUrl set we respect NODE_PATH
21 | // Note that NODE_PATH is deprecated and will be removed
22 | // in the next major release of create-react-app.
23 |
24 | const nodePath = process.env.NODE_PATH || '';
25 | return nodePath.split(path.delimiter).filter(Boolean);
26 | }
27 |
28 | const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
29 |
30 | // We don't need to do anything if `baseUrl` is set to `node_modules`. This is
31 | // the default behavior.
32 | if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
33 | return null;
34 | }
35 |
36 | // Allow the user set the `baseUrl` to `appSrc`.
37 | if (path.relative(paths.appSrc, baseUrlResolved) === '') {
38 | return [paths.appSrc];
39 | }
40 |
41 | // If the path is equal to the root directory we ignore it here.
42 | // We don't want to allow importing from the root directly as source files are
43 | // not transpiled outside of `src`. We do allow importing them with the
44 | // absolute path (e.g. `src/Components/Button.js`) but we set that up with
45 | // an alias.
46 | if (path.relative(paths.appPath, baseUrlResolved) === '') {
47 | return null;
48 | }
49 |
50 | // Otherwise, throw an error.
51 | throw new Error(
52 | chalk.red.bold(
53 | "Your project's `baseUrl` can only be set to `src` or `node_modules`." +
54 | ' Create React App does not support other values at this time.'
55 | )
56 | );
57 | }
58 |
59 | /**
60 | * Get webpack aliases based on the baseUrl of a compilerOptions object.
61 | *
62 | * @param {*} options
63 | */
64 | function getWebpackAliases(options = {}) {
65 | const baseUrl = options.baseUrl;
66 |
67 | if (!baseUrl) {
68 | return {};
69 | }
70 |
71 | const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
72 |
73 | if (path.relative(paths.appPath, baseUrlResolved) === '') {
74 | return {
75 | src: paths.appSrc,
76 | };
77 | }
78 | }
79 |
80 | /**
81 | * Get jest aliases based on the baseUrl of a compilerOptions object.
82 | *
83 | * @param {*} options
84 | */
85 | function getJestAliases(options = {}) {
86 | const baseUrl = options.baseUrl;
87 |
88 | if (!baseUrl) {
89 | return {};
90 | }
91 |
92 | const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
93 |
94 | if (path.relative(paths.appPath, baseUrlResolved) === '') {
95 | return {
96 | '^src/(.*)$': '/src/$1',
97 | };
98 | }
99 | }
100 |
101 | function getModules() {
102 | // Check if TypeScript is setup
103 | const hasTsConfig = fs.existsSync(paths.appTsConfig);
104 | const hasJsConfig = fs.existsSync(paths.appJsConfig);
105 |
106 | if (hasTsConfig && hasJsConfig) {
107 | throw new Error(
108 | 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
109 | );
110 | }
111 |
112 | let config;
113 |
114 | // If there's a tsconfig.json we assume it's a
115 | // TypeScript project and set up the config
116 | // based on tsconfig.json
117 | if (hasTsConfig) {
118 | const ts = require(resolve.sync('typescript', {
119 | basedir: paths.appNodeModules,
120 | }));
121 | config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
122 | // Otherwise we'll check if there is jsconfig.json
123 | // for non TS projects.
124 | } else if (hasJsConfig) {
125 | config = require(paths.appJsConfig);
126 | }
127 |
128 | config = config || {};
129 | const options = config.compilerOptions || {};
130 |
131 | const additionalModulePaths = getAdditionalModulePaths(options);
132 |
133 | return {
134 | additionalModulePaths: additionalModulePaths,
135 | webpackAliases: getWebpackAliases(options),
136 | jestAliases: getJestAliases(options),
137 | hasTsConfig,
138 | };
139 | }
140 |
141 | module.exports = getModules();
142 |
--------------------------------------------------------------------------------
/web-dapp/config/paths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
6 |
7 | // Make sure any symlinks in the project folder are resolved:
8 | // https://github.com/facebook/create-react-app/issues/637
9 | const appDirectory = fs.realpathSync(process.cwd());
10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
11 |
12 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
13 | // "public path" at which the app is served.
14 | // webpack needs to know it to put the right
54 |
61 |
62 |