├── .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 | -------------------------------------------------------------------------------- /web-dapp/scripts/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Do this as the first thing so that any code reading it knows the right env. 4 | process.env.BABEL_ENV = 'test'; 5 | process.env.NODE_ENV = 'test'; 6 | process.env.PUBLIC_URL = ''; 7 | 8 | // Makes the script crash on unhandled rejections instead of silently 9 | // ignoring them. In the future, promise rejections that are not handled will 10 | // terminate the Node.js process with a non-zero exit code. 11 | process.on('unhandledRejection', err => { 12 | throw err; 13 | }); 14 | 15 | // Ensure environment variables are read. 16 | require('../config/env'); 17 | 18 | 19 | const jest = require('jest'); 20 | const execSync = require('child_process').execSync; 21 | let argv = process.argv.slice(2); 22 | 23 | function isInGitRepository() { 24 | try { 25 | execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }); 26 | return true; 27 | } catch (e) { 28 | return false; 29 | } 30 | } 31 | 32 | function isInMercurialRepository() { 33 | try { 34 | execSync('hg --cwd . root', { stdio: 'ignore' }); 35 | return true; 36 | } catch (e) { 37 | return false; 38 | } 39 | } 40 | 41 | // Watch unless on CI or explicitly running all tests 42 | if ( 43 | !process.env.CI && 44 | argv.indexOf('--watchAll') === -1 && 45 | argv.indexOf('--watchAll=false') === -1 46 | ) { 47 | // https://github.com/facebook/create-react-app/issues/5210 48 | const hasSourceControl = isInGitRepository() || isInMercurialRepository(); 49 | argv.push(hasSourceControl ? '--watch' : '--watchAll'); 50 | } 51 | 52 | 53 | jest.run(argv); 54 | -------------------------------------------------------------------------------- /web-dapp/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | const { getByText } = render(); 7 | const linkElement = getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /web-dapp/src/abi/address_map.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": { 3 | "USDT": "0xdAC17F958D2ee523a2206206994597C13D831ec7", 4 | "dUSDT": "0x868277d475E0e475E38EC5CdA2d9C83B5E1D9fc8", 5 | 6 | "USDC": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", 7 | "dUSDC": "0x16c9cF62d8daC4a38FB50Ae5fa5d51E9170F3179", 8 | 9 | "DAI": "0x6B175474E89094C44Da98b954EedeAC495271d0F", 10 | "dDAI": "0x02285AcaafEB533e03A7306C55EC031297df9224" 11 | }, 12 | 13 | "rinkeby": { 14 | "USDT": "0xD9BA894E0097f8cC2BBc9D24D308b98e36dc6D02", 15 | "dUSDT": "0x37bDa3a6C061C4fB16aC70668160a54081eb1B3D", 16 | "USDC": "0x4DBCdF9B62e891a7cec5A2568C3F4FAF9E8Abe2b", 17 | "dUSDC": "0x8e6b04988fd7ecd45e1b180f9476afd39e79dfa1" 18 | }, 19 | 20 | "kovan": { 21 | "USDT": "0x07de306FF27a2B630B1141956844eB1552B956B5", 22 | "dUSDT": "0x4c153111272cB826A80627c4A51c48ccB7d3153B", 23 | 24 | "USDC": "0xb7a4F3E9097C08dA09517b5aB877F7a917224ede", 25 | "dUSDC": "0xc801DF89680D00ABEd5599e9EE6b35ecb54d49Fc", 26 | 27 | "DAI": "0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa", 28 | "dDAI": "0x19205bFDaf1BC9fC8705eA9a73f560572fb8F455", 29 | 30 | "TUSD": "0x1c4a937d171752e1313D70fb16Ae2ea02f86303e", 31 | "dTUSD": "0x938C3681fE2Ef6D3A722cb387F4AE79D16911c3A", 32 | 33 | "baseData": "0x80df99FAeaD7BDcf54FF18554860b3A24e4D68B5", 34 | "Aave_Handler": "0xAfA9171828d3B2345638021647598F15F77c0e3A", 35 | "Compound_Handler": "0xfc2F818A8b9761fC0852D2702B82a5392dbbcfe1", 36 | "Internal_Handler": "0xe5683ccab068627d9EA9a35f988c371Fc1727aF5", 37 | 38 | "DTokenCommonData":"0xdfad38b0e85712a8dd1928842ef2eec45eddcfe3", 39 | "Handler":{ 40 | "0xe5683ccab068627d9EA9a35f988c371Fc1727aF5":"Internal", 41 | "0xfc2F818A8b9761fC0852D2702B82a5392dbbcfe1":"Compound", 42 | "0x0d4c0A915c933FA197B965C294c933514CCCf4B1":"Compound1", 43 | "0xAfA9171828d3B2345638021647598F15F77c0e3A":"Aave" 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /web-dapp/src/abi/constance.json: -------------------------------------------------------------------------------- 1 | { 2 | "gas": 1250000, 3 | "url": "https://markets.dforce.network/api/v1/getBanlanceInfo/", 4 | "url_test": "https://testapi.dforce.network/api/v1/getBanlanceInfo/", 5 | "url_apy": "https://markets.dforce.network/api/v1/getApy/?net=" 6 | } -------------------------------------------------------------------------------- /web-dapp/src/component/FAQ/components/SvgIcon/index.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | 4 | const SvgIcon = (props) => { 5 | const { iconClass, fill, className, alt } = props; 6 | 7 | return ( 8 | 15 | ); 16 | }; 17 | 18 | SvgIcon.propTypes = { 19 | // svg名字 20 | iconClass: PropTypes.string.isRequired, 21 | // 填充颜色 22 | fill: PropTypes.string, 23 | className: PropTypes.string, 24 | alt: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), 25 | }; 26 | 27 | SvgIcon.defaultProps = { 28 | fill: "currentColor", 29 | }; 30 | 31 | export default SvgIcon; 32 | -------------------------------------------------------------------------------- /web-dapp/src/component/FAQ/svg/collapse.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | btn_collapse_dl 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /web-dapp/src/component/FAQ/svg/fqa1.svg: -------------------------------------------------------------------------------- 1 | icon-FAQ1 -------------------------------------------------------------------------------- /web-dapp/src/component/FAQ/svg/fqa2.svg: -------------------------------------------------------------------------------- 1 | icon-FAQ2 -------------------------------------------------------------------------------- /web-dapp/src/component/FAQ/svg/fqa3.svg: -------------------------------------------------------------------------------- 1 | icon-FAQ3 -------------------------------------------------------------------------------- /web-dapp/src/component/FAQ/svg/fqa4.svg: -------------------------------------------------------------------------------- 1 | icon-FAQ4 -------------------------------------------------------------------------------- /web-dapp/src/component/FAQ/svg/fqa5.svg: -------------------------------------------------------------------------------- 1 | icon-FAQ5 -------------------------------------------------------------------------------- /web-dapp/src/component/FAQ/svg/fqa6.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | img_fqa_6 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /web-dapp/src/component/FAQ/svg/fqa7.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | img_fqa_7 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /web-dapp/src/component/FAQ/svg/unfold.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | btn_Unfold_dl 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /web-dapp/src/component/SvgIcon/index.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | import styles from "./style.scss"; 4 | 5 | const SvgIcon = props => { 6 | const { iconClass, fill } = props; 7 | 8 | return ( 9 | 14 | ); 15 | }; 16 | 17 | SvgIcon.propTypes = { 18 | // svg名字 19 | iconClass: PropTypes.string.isRequired, 20 | // 填充颜色 21 | fill: PropTypes.string 22 | }; 23 | 24 | SvgIcon.defaultProps = { 25 | fill: "currentColor" 26 | }; 27 | 28 | export default SvgIcon; 29 | -------------------------------------------------------------------------------- /web-dapp/src/component/SvgIcon/style.scss: -------------------------------------------------------------------------------- 1 | .svg-class { 2 | display: inline-block; 3 | overflow: hidden; 4 | font-size: 14px; 5 | min-width: 14px; 6 | width: 1em; 7 | height: 1em; 8 | } -------------------------------------------------------------------------------- /web-dapp/src/component/top.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import "./top.scss"; 3 | // add i18n. 4 | import { IntlProvider, FormattedMessage } from 'react-intl'; 5 | import en_US from '../language/en_US.js'; 6 | import zh_CN from '../language/zh_CN'; 7 | import logo_xswap from '../images/logo-dforce.svg'; 8 | import arrow_down from '../images/arrow-down.svg'; 9 | 10 | 11 | export default class top extends Component { 12 | 13 | openOnEtherscan = (my_account) => { 14 | if (this.props.net_type === 'rinkeby') { 15 | my_account = 'https://rinkeby.etherscan.io/address/' + my_account; 16 | } else { 17 | my_account = 'https://etherscan.io/address/' + my_account; 18 | } 19 | window.open(my_account, "_blank"); 20 | } 21 | 22 | render() { 23 | return ( 24 | 25 |
26 |
27 | 28 |
29 | 30 | { 31 | this.props.account && 32 |
33 | 34 | { this.openOnEtherscan(this.props.account) }}> 35 | {this.props.account.slice(0, 4) + '...' + this.props.account.slice(-4)} 36 | 37 |
38 | } 39 | 40 | { 41 | !this.props.account && 42 |
{ this.props.fn_connect() }}> 43 | 44 |
45 | } 46 | 47 |
48 |
49 |
50 | Yield Market 51 | 52 |
53 |
54 | 62 |
63 |
64 | 65 |
66 |
67 | dForce Stablecoin 68 | 69 |
70 |
71 | 85 |
86 |
87 |
88 |
89 | 90 |
91 | 92 |
93 |
94 | ) 95 | } 96 | } 97 | 98 | -------------------------------------------------------------------------------- /web-dapp/src/component/top.scss: -------------------------------------------------------------------------------- 1 | $theme-color: #D4A454; 2 | 3 | // >768 4 | @media screen and (min-width: 768px) { 5 | .top { 6 | width: 1120px; 7 | // background-color: red; 8 | height: 70px; 9 | margin: 0 auto; 10 | 11 | .top-left { 12 | float: left; 13 | padding-top: 25px; 14 | 15 | img { 16 | width: 124px; 17 | } 18 | } 19 | 20 | .top-right-connect { 21 | float: right; 22 | cursor: pointer; 23 | width: 124px; 24 | text-align: center; 25 | height: 30px; 26 | line-height: 30px; 27 | background: rgba(41, 187, 146, 1); 28 | border-radius: 3px; 29 | font-size: 16px; 30 | font-weight: 500; 31 | color: rgba(255, 255, 255, 1); 32 | margin-top: 20px; 33 | position: relative; 34 | padding-left: 5px; 35 | 36 | .top-dot { 37 | position: absolute; 38 | width: 7px; 39 | height: 7px; 40 | // background-color: red; 41 | border-radius: 50%; 42 | left: 5px; 43 | top: 12px; 44 | } 45 | } 46 | 47 | .top-meun { 48 | float: right; 49 | 50 | .top-meun-item { 51 | // background-color: green; 52 | float: right; 53 | position: relative; 54 | margin-top: 28px; 55 | padding-bottom: 20px; 56 | width: 150px; 57 | margin-right: 36px; 58 | cursor: pointer; 59 | 60 | .item-fixed { 61 | font-size: 16px; 62 | font-weight: 500; 63 | color: rgba(37, 33, 82, 1); 64 | position: relative; 65 | 66 | .arrow-down { 67 | transition: 0.3s; 68 | position: absolute; 69 | right: 0px; 70 | width: 8px; 71 | top: 6px; 72 | } 73 | 74 | .img-right45 { 75 | right: 40px; 76 | } 77 | } 78 | 79 | .item-more { 80 | transition: 0.3s; 81 | display: none; 82 | position: absolute; 83 | // background-color: red; 84 | top: 30px; 85 | width: 150px; 86 | background: rgba(255, 255, 255, 1); 87 | border: 1px solid rgba(229, 230, 242, 1); 88 | box-shadow: 0px 6px 19px 0px rgba(7, 2, 55, 0.1); 89 | border-radius: 4px; 90 | padding-left: 10px; 91 | padding-bottom: 10px; 92 | padding-top: 10px; 93 | z-index: 9999; 94 | 95 | ul { 96 | li { 97 | // height: 50px; 98 | margin-bottom: 15px; 99 | 100 | a { 101 | text-decoration: none; 102 | font-size: 16px; 103 | font-weight: 500; 104 | color: rgba(37, 33, 82, 1); 105 | transition: 0.3s; 106 | } 107 | 108 | a:hover { 109 | color: $theme-color; 110 | } 111 | 112 | .title { 113 | display: block; 114 | padding-top: 10px; 115 | padding-bottom: 10px; 116 | } 117 | 118 | .details { 119 | display: block; 120 | font-size: 14px; 121 | font-weight: 400; 122 | color: rgba(139, 142, 165, 1); 123 | line-height: 22px; 124 | } 125 | } 126 | } 127 | } 128 | } 129 | 130 | .top-meun-item:hover { 131 | .item-more { 132 | display: block; 133 | } 134 | 135 | .item-fixed { 136 | .arrow-down { 137 | transform: rotate(180deg); 138 | } 139 | } 140 | } 141 | } 142 | } 143 | } 144 | 145 | 146 | // 147 | @media screen and (max-width: 767px) { 148 | .top { 149 | display: none; 150 | } 151 | } -------------------------------------------------------------------------------- /web-dapp/src/entry.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import App from './App'; 3 | import Admin from './admin'; 4 | import Home from './component/Home'; 5 | import App_bsc from './App-bsc'; 6 | import { BrowserRouter as Router, Route } from "react-router-dom"; 7 | 8 | class Entry extends Component { 9 | render() { 10 | return ( 11 | 12 | {/* } /> 13 | } /> 14 | } /> */} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ) 23 | } 24 | } 25 | export default Entry; -------------------------------------------------------------------------------- /web-dapp/src/icons/index.js: -------------------------------------------------------------------------------- 1 | const requireAll = requireContext => requireContext.keys().map(requireContext); 2 | const svgs = require.context("./svg", false, /\.svg$/); 3 | requireAll(svgs); 4 | -------------------------------------------------------------------------------- /web-dapp/src/icons/svg/DAI.svg: -------------------------------------------------------------------------------- 1 | 23 -------------------------------------------------------------------------------- /web-dapp/src/icons/svg/USDC.svg: -------------------------------------------------------------------------------- 1 | USDC -------------------------------------------------------------------------------- /web-dapp/src/icons/svg/USDT.svg: -------------------------------------------------------------------------------- 1 | Home_TUSD logo -------------------------------------------------------------------------------- /web-dapp/src/icons/svg/content.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web-dapp/src/icons/svg/operation.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web-dapp/src/icons/svg/room.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web-dapp/src/images/BTC.svg: -------------------------------------------------------------------------------- 1 | imBTC-logo -------------------------------------------------------------------------------- /web-dapp/src/images/BUSD.svg: -------------------------------------------------------------------------------- 1 | BUSD-logo -------------------------------------------------------------------------------- /web-dapp/src/images/DAI.svg: -------------------------------------------------------------------------------- 1 | 23 -------------------------------------------------------------------------------- /web-dapp/src/images/Discord.svg: -------------------------------------------------------------------------------- 1 | 社区图标-5 -------------------------------------------------------------------------------- /web-dapp/src/images/HBTC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dforce-network/dToken/05bda1f755becb7e3706c648aca0af57b69b9822/web-dapp/src/images/HBTC.png -------------------------------------------------------------------------------- /web-dapp/src/images/HBTC.svg: -------------------------------------------------------------------------------- 1 | HBTC-logo -------------------------------------------------------------------------------- /web-dapp/src/images/LinkedIn.svg: -------------------------------------------------------------------------------- 1 | 社区图标-6 -------------------------------------------------------------------------------- /web-dapp/src/images/Reddit.svg: -------------------------------------------------------------------------------- 1 | 社区图标-4 -------------------------------------------------------------------------------- /web-dapp/src/images/TUSD.svg: -------------------------------------------------------------------------------- 1 | TUSD -------------------------------------------------------------------------------- /web-dapp/src/images/USDC.svg: -------------------------------------------------------------------------------- 1 | USDC -------------------------------------------------------------------------------- /web-dapp/src/images/USDT.svg: -------------------------------------------------------------------------------- 1 | Home_TUSD logo -------------------------------------------------------------------------------- /web-dapp/src/images/USDx.svg: -------------------------------------------------------------------------------- 1 | Home_USDx logo -------------------------------------------------------------------------------- /web-dapp/src/images/UUDD.svg: -------------------------------------------------------------------------------- 1 | Home_USDx logo -------------------------------------------------------------------------------- /web-dapp/src/images/WBTC.svg: -------------------------------------------------------------------------------- 1 | WBTC-logo -------------------------------------------------------------------------------- /web-dapp/src/images/WETH.svg: -------------------------------------------------------------------------------- 1 | Home_WETH logo -------------------------------------------------------------------------------- /web-dapp/src/images/Youtube.svg: -------------------------------------------------------------------------------- 1 | 社区图标-7 -------------------------------------------------------------------------------- /web-dapp/src/images/arrow-down.svg: -------------------------------------------------------------------------------- 1 | 导航下拉箭头 -------------------------------------------------------------------------------- /web-dapp/src/images/arrow_d.svg: -------------------------------------------------------------------------------- 1 | icon-xl -------------------------------------------------------------------------------- /web-dapp/src/images/arrow_down.svg: -------------------------------------------------------------------------------- 1 | 下拉-三角 -------------------------------------------------------------------------------- /web-dapp/src/images/close-new.svg: -------------------------------------------------------------------------------- 1 | iocn-gb -------------------------------------------------------------------------------- /web-dapp/src/images/close.svg: -------------------------------------------------------------------------------- 1 | icon-dk -------------------------------------------------------------------------------- /web-dapp/src/images/erweima.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dforce-network/dToken/05bda1f755becb7e3706c648aca0af57b69b9822/web-dapp/src/images/erweima.png -------------------------------------------------------------------------------- /web-dapp/src/images/exchange.svg: -------------------------------------------------------------------------------- 1 | icon-qh -------------------------------------------------------------------------------- /web-dapp/src/images/exchange_mob.svg: -------------------------------------------------------------------------------- 1 | 上下切换 -------------------------------------------------------------------------------- /web-dapp/src/images/imBTC.svg: -------------------------------------------------------------------------------- 1 | imBTC-logo -------------------------------------------------------------------------------- /web-dapp/src/images/is_selected.svg: -------------------------------------------------------------------------------- 1 | iocn-xz -------------------------------------------------------------------------------- /web-dapp/src/images/lock.svg: -------------------------------------------------------------------------------- 1 | icon-suo -------------------------------------------------------------------------------- /web-dapp/src/images/logo-dforce.svg: -------------------------------------------------------------------------------- 1 | dforce -------------------------------------------------------------------------------- /web-dapp/src/images/logo-xswap.svg: -------------------------------------------------------------------------------- 1 | xswap-logo -------------------------------------------------------------------------------- /web-dapp/src/images/logo_exchange.svg: -------------------------------------------------------------------------------- 1 | icon-jh -------------------------------------------------------------------------------- /web-dapp/src/images/logo_exchange_fail.svg: -------------------------------------------------------------------------------- 1 | 错误提示icon -------------------------------------------------------------------------------- /web-dapp/src/images/logo_exchange_mint.svg: -------------------------------------------------------------------------------- 1 | 存入icon -------------------------------------------------------------------------------- /web-dapp/src/images/logo_exchange_pendding.svg: -------------------------------------------------------------------------------- 1 | 执行中 -------------------------------------------------------------------------------- /web-dapp/src/images/logo_exchange_redeem.svg: -------------------------------------------------------------------------------- 1 | 取出icon -------------------------------------------------------------------------------- /web-dapp/src/images/medium.svg: -------------------------------------------------------------------------------- 1 | icon-medium -------------------------------------------------------------------------------- /web-dapp/src/images/no-history.svg: -------------------------------------------------------------------------------- 1 | icon-History -------------------------------------------------------------------------------- /web-dapp/src/images/no_support.svg: -------------------------------------------------------------------------------- 1 | Wrong Network-icon -------------------------------------------------------------------------------- /web-dapp/src/images/pax.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dforce-network/dToken/05bda1f755becb7e3706c648aca0af57b69b9822/web-dapp/src/images/pax.png -------------------------------------------------------------------------------- /web-dapp/src/images/show-tips.svg: -------------------------------------------------------------------------------- 1 | 错误提示图标 -------------------------------------------------------------------------------- /web-dapp/src/images/telegram.svg: -------------------------------------------------------------------------------- 1 | icon-telegram -------------------------------------------------------------------------------- /web-dapp/src/images/twitter.svg: -------------------------------------------------------------------------------- 1 | icon-twitter -------------------------------------------------------------------------------- /web-dapp/src/images/up.svg: -------------------------------------------------------------------------------- 1 | icon-翻译切换箭头 -------------------------------------------------------------------------------- /web-dapp/src/images/wallet-metamask.svg: -------------------------------------------------------------------------------- 1 | logo-metamask -------------------------------------------------------------------------------- /web-dapp/src/images/weixin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | logo-weixin 10 | 11 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /web-dapp/src/images/witch.svg: -------------------------------------------------------------------------------- 1 | 箭头icon -------------------------------------------------------------------------------- /web-dapp/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | 9 | /* -moz-user-select: none; 10 | -o-user-select: none; 11 | -khtml-user-select: none; 12 | -webkit-user-select: none; 13 | -ms-user-select: none; 14 | user-select: none; */ 15 | } 16 | 17 | * { 18 | margin: 0; 19 | padding: 0; 20 | border: 0; 21 | font-size: 100%; 22 | font: inherit; 23 | vertical-align: baseline; 24 | box-sizing: border-box; 25 | } 26 | 27 | body { 28 | line-height: 1; 29 | background: #F8F9FF !important; 30 | } 31 | 32 | ol, 33 | ul { 34 | list-style: none; 35 | } 36 | 37 | table { 38 | border-collapse: collapse; 39 | border-spacing: 0; 40 | } 41 | 42 | input, 43 | button, 44 | a { 45 | outline: 0 none !important; 46 | /* blr: expression(this.onFocus=this.blur()); */ 47 | } 48 | 49 | input, 50 | input:focus, 51 | input:active { 52 | user-select: text; 53 | -webkit-user-select: text; 54 | zoom: 1 55 | } 56 | 57 | 58 | input[type=text] { 59 | -moz-appearance: textfield; 60 | } 61 | 62 | input[type=text]::-webkit-inner-spin-button, 63 | input[type=text]::-webkit-outer-spin-button { 64 | -webkit-appearance: none; 65 | margin: 0; 66 | } 67 | 68 | input[type="text"] { 69 | -moz-appearance: textfield; 70 | } 71 | 72 | input::-webkit-outer-spin-button, 73 | input::-webkit-inner-spin-button { 74 | -webkit-appearance: none; 75 | } 76 | 77 | input[type="number"] { 78 | -moz-appearance: textfield; 79 | } 80 | 81 | .ant-dropdown-menu-item { 82 | /* background-color: red!important; */ 83 | width: 100%; 84 | } 85 | 86 | .ant-dropdown-menu-item img { 87 | /* background-color: red!important; */ 88 | width: 16px; 89 | margin-right: 6px; 90 | margin-top: -2px; 91 | } 92 | 93 | .ant-tabs-nav-wrap::after { 94 | /* content: ''; */ 95 | z-index: 9999 !important; 96 | width: 0 !important; 97 | } 98 | 99 | .ant-tabs-nav-wrap::before { 100 | /* content: ''; */ 101 | z-index: 9999 !important; 102 | width: 0 !important; 103 | } 104 | 105 | .ant-tabs-nav-more { 106 | display: none !important; 107 | } -------------------------------------------------------------------------------- /web-dapp/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import Entry from './entry'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | 8 | ReactDOM.render(, document.getElementById('root')); 9 | 10 | // If you want your app to work offline and load faster, you can change 11 | // unregister() to register() below. Note this comes with some pitfalls. 12 | // Learn more about service workers: https://bit.ly/CRA-PWA 13 | serviceWorker.unregister(); 14 | -------------------------------------------------------------------------------- /web-dapp/src/language/en_US.js: -------------------------------------------------------------------------------- 1 | const en_US = { 2 | FORUM:'FORUM', 3 | VOTE:'VOTE', 4 | FARM:'FARM', 5 | LEND:'LEND', 6 | Governance__content: 'Propose & vote', 7 | Airdrop: 'AIRDROP', 8 | on_ETH: 'The data on this page comes from the Ethereum Mainnet.', 9 | on_BSC: 'The data on this page comes from the Binance Smart Chain.', 10 | to_ETH: 'Switch to Ethereum', 11 | to_BSC: 'Switch to BSC', 12 | Legacy_Withdraw: 'Legacy Withdraw', 13 | USR_subTitle: 'USDx saving rate', 14 | goldx: 'GOLDx', 15 | goldx_detail: 'Token backed by physical gold', 16 | Yield_Markets: 'YIELD MARKETS', 17 | Yield_Markets_detail: 'A yield aggregator', 18 | slogan_title_plus: 'The Most Accessible High Yield Aggregator', 19 | slogan_title: 'dForce Yield Markets', 20 | Market_Size: 'Market Size', 21 | Asset: 'Asset', 22 | All_Markets: 'All Markets', 23 | it_is_detail2: 'Attention: Only users have access and full control over your funds and we do not hold your asset. Please make sure to keep your private key safe as we are unable to retrieve your private key, access your account, reset your password or reverse transaction. It would be extremely upsetting if you lost your private key as you will permanently lose access to your funds. ', 24 | it_is_detail1: 'The Yield Markets is a smart contract deployed on Ethereum, with security audit conducted by Trail of Bits. Please click here to view the full report. ', 25 | it_is: 'Is it safe to use the Yield Markets?', 26 | detail4: 'Supporting a broad range of DeFi farming strategies for maximized risk-adjusted yield and ROI.', 27 | title4: 'The Most Attractive Return', 28 | detail3: 'Flexible deposit and withdrawal at any time', 29 | title3: 'High Liquidity', 30 | detail2: 'Seeking the most favorable yield by switching among protocols or markets on a pool basis, so to reduce transaction cost', 31 | title2: 'Cost-Efficient', 32 | detail1: 'Providing an all-in-one solution for retail participants to farm the most attractive yields across selected DeFi protocols with the best interest rates, high liquidity availability.', 33 | title1: 'All-in-One Farming', 34 | Highlights: 'Highlights of Yield Market?', 35 | Frequently: 'Frequently Asked Questions', 36 | how_does_detail: 'The Yield Market is a yield aggregator that connects lending/liquidity protocols in the background in order to provide users with the best return on their assets. It aims to farm the most attractive risk-adjusted yield by supplying pooled capital to lending protocols (Compound, Aave, dForce Lending etc) and automatically rebalance to ensure that assets are being lent to the one with the best yield. We will evaluate and integrate with more DeFi protocols in the future, including dForce lending protocol and our hybrid lending platform.', 37 | how_does: 'How does the Yield Market earn interests?', 38 | what_is_yield_detail: 'The Yield Markets is the marketplace that provide the best yield tokens and it is the most accessible yield aggregator to farm the most attractive risk-adjusted yield across DeFi protocols. The Yield Markets now supports USDx, GOLDx, USDT, USDX, and DAI. Depositing supported tokens into the Yield Markets, you will receive corresponding dToken on a pro rata basis (i.e. depositing USDT to receive dUSDT). Each dToken represents a pro rata claim of the underlying token plus yields generated.', 39 | what_is_yield: 'What is the Yield Market?', 40 | what_is_df_detail: 'dForce advocates for building an integrated and interoperable open finance and monetary protocol matrix serving as unified liquidity pool and back-bone infrastructure for DeFi and open finance applications.', 41 | what_is_df: 'What is dForce?', 42 | Audit_Reports: 'Audit Reports', 43 | Enabling: 'ENABLING…', 44 | withdraw_balance: 'Available to Withdraw', 45 | ENABLE: 'ENABLE', 46 | brewing: ' brewing.', 47 | You_have: 'You have ', 48 | Deposit: 'Deposit', 49 | Withdraw: 'Withdraw', 50 | WITHDRAW: 'WITHDRAW', 51 | DEPOSIT: 'DEPOSIT', 52 | no_data: 'No Data', 53 | mint: 'Mint', 54 | redeem: 'Redeem', 55 | assets: 'Asset', 56 | net_value: 'Pool', 57 | APY: 'APY', 58 | REDEEM: 'REDEEM', 59 | you_w_receive: 'You will receive ', 60 | MINT: 'MINT', 61 | send: 'SEND', 62 | recive: 'RECEIVE', 63 | send_l: 'Send', 64 | recive_l: 'Receive', 65 | history: 'Recent Transactions', 66 | swap: 'SWAP', 67 | connect: 'Connect', 68 | slogon: 'Stable Assets Swap', 69 | no_history: 'No History', 70 | Contract_US: 'Contact', 71 | Community: 'Community', 72 | Resource: 'Resource', 73 | Insufficient_Balance: 'Insufficient Balance', 74 | Insufficient_Liquidity: 'Insufficient Liquidity', 75 | balance: 'Balance', 76 | Not_SUPPORTED: 'NOT SUPPORTED', 77 | Exchange_Market: 'TRADE', 78 | dForce_Stablecoin: 'ASSETS', 79 | Portal: 'An indexed stablecoin', 80 | Instant_Swap_of_Stable_Assets: 'DEX aggregator', 81 | DF_token_distribute_system: 'Incentivized DF distribution', 82 | Governance: 'GOVERNANCE' 83 | } 84 | export default en_US; -------------------------------------------------------------------------------- /web-dapp/src/language/zh_CN.js: -------------------------------------------------------------------------------- 1 | const zh_CN = { 2 | FORUM:'论坛', 3 | VOTE:'投票', 4 | FARM:'挖矿', 5 | LEND:'借贷', 6 | Governance__content: '提议和投票', 7 | Airdrop: '空投', 8 | on_ETH: '页面中的数据来源于以太坊主网', 9 | on_BSC: '页面中的数据来源于币安智能链', 10 | to_ETH: '切换到Ethereum', 11 | to_BSC: '切换到BSC', 12 | Legacy_Withdraw: '旧 版 取 回', 13 | USR_subTitle: 'USDx系统利息', 14 | goldx: '黄金代币', 15 | goldx_detail: '锚定实物黄金的代币', 16 | Yield_Markets: '生息市场', 17 | Yield_Markets_detail: '利息聚合器', 18 | slogan_title_plus: '轻松上手的高收益稳定币余额宝', 19 | slogan_title: 'dForce生息市场', 20 | Market_Size: '存款总量', 21 | Asset: '资产', 22 | All_Markets: '市场', 23 | it_is_detail2: '友情提示:仅用户本人只有用户本人能够通过密钥管理自己存入智能合约的资产,其他任何人都无法控制或更改交易。请务必妥善保管您的私钥,由于我们没有访问和更改个人账号的权限,所以无法协助用户找回或更改私钥。一旦用户不慎丢失私钥,您将无法再访问自己的账户,并将永久失去账户内的资产。', 24 | it_is_detail1: '生息市场是部署在以太坊上的智能合约,安全审计由Trail of Bits完成,请点击这里查看完整报告。', 25 | it_is: '生息市场的安全性如何?', 26 | detail4: '通过接入不同的DeFi市场,同时配合DeFi代币激励挖矿,以此获得风险调整后的最优回报', 27 | title4: '最优回报', 28 | detail3: '随存随取,灵活方便', 29 | title3: '高流动性', 30 | detail2: '在不同协议和代币池间切换寻求最高收益,调仓费用由所有用户共同承担,有效降低了调仓成本', 31 | title2: '费用低廉', 32 | detail1: '将资金配置到优选DeFi协议(兼顾高收益和高流动性)参与流动性挖矿,小白用户也能轻松上手', 33 | title1: '一键挖矿', 34 | Highlights: '生息市场的主要优势?', 35 | Frequently: '常见问题', 36 | how_does_detail: '生息市场作为一个利息聚合器,在底层打通了借贷/流动性协议,从而可以为用户获取市场上最高的存款利息。生息市场将汇集的资金投入Compound和Aave,并通过自动调仓来获取最优回报。我们将持续评估和整合更多的开放式金融协议,包括dForce借贷协议和混合型借贷平台。', 37 | how_does: '生息市场的利息来源?', 38 | what_is_yield_detail: '生息市场(Yield Markets)是dForce推出的第二个核心资产协议,旨在成为高收益型稳定币余额宝,为用户获取市场上回报最高的DeFi流动性挖矿收益。目前支持的币种包括USDx, GOLDx, USDT, USDC, DAI。用户将代币存入生息市场将自动获得相应比例的dToken(例如,存入USDx将获得dUSDx),每枚dToken都代表了底层储备代币和其所对应的收益权。', 39 | what_is_yield: '生息市场是什么?', 40 | what_is_df_detail: 'dForce旨在为基于区块链技术开发的开放式金融和货币协议应用,构建一个集成的和互通的协议矩阵,提供一个统一的流动性池的基础设施服务于开放式金融网络。', 41 | what_is_df: 'dForce是什么?', 42 | Audit_Reports: '审计报告', 43 | Enabling: '授权中…', 44 | withdraw_balance: '可取数量', 45 | ENABLE: '授权', 46 | brewing: ' 正在计息', 47 | You_have: '您有 ', 48 | Deposit: '存入', 49 | Withdraw: '取回', 50 | WITHDRAW: '取回', 51 | DEPOSIT: '存入', 52 | no_data: '没有数据', 53 | mint: '存入', 54 | redeem: '取回', 55 | assets: '资产', 56 | net_value: '市场存款总量', 57 | APY: '年化利率', 58 | REDEEM: '取回', 59 | you_w_receive: '你会收到', 60 | MINT: '存入', 61 | send: '发送', 62 | recive: '接收', 63 | send_l: '发送', 64 | recive_l: '接收', 65 | history: '最近记录', 66 | swap: '兑换', 67 | connect: '连接钱包', 68 | slogon: '稳定资产闪兑', 69 | no_history: '没有历史记录', 70 | Contract_US: '联系我们', 71 | Community: '社区', 72 | Resource: '资源', 73 | Insufficient_Balance: '余额不足', 74 | Insufficient_Liquidity: '流动性不足', 75 | balance: '余额', 76 | Not_SUPPORTED: '不支持兑换', 77 | Exchange_Market: '交易', 78 | dForce_Stablecoin: '资产', 79 | Portal: '合成型稳定币', 80 | Instant_Swap_of_Stable_Assets: '去中心化交易聚合器', 81 | DF_token_distribute_system: 'DF激励分发', 82 | Governance: '治理' 83 | } 84 | export default zh_CN; -------------------------------------------------------------------------------- /web-dapp/src/logo.svg: -------------------------------------------------------------------------------- 1 | lendf_logo1 -------------------------------------------------------------------------------- /web-dapp/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom/extend-expect'; 6 | -------------------------------------------------------------------------------- /web-dapp/src/style/model.scss: -------------------------------------------------------------------------------- 1 | $theme-color: #D4A454; 2 | 3 | .ant-btn, 4 | .ant-btn:hover, 5 | .ant-btn:focus { 6 | color: #fff; 7 | background: $theme-color; 8 | border-color: $theme-color; 9 | } 10 | 11 | .ant-modal { 12 | width: 660px !important; 13 | } 14 | 15 | 16 | .modal-title { 17 | font-size: 18px; 18 | font-weight: bold; 19 | color: rgba(67, 73, 118, 1); 20 | text-align: center; 21 | } 22 | 23 | .item-addr { 24 | display: flex; 25 | justify-content: space-between; 26 | margin-top: 16px; 27 | 28 | textarea { 29 | width: 456px; 30 | height: 100px; 31 | background: rgba(255, 255, 255, 1); 32 | border: 1px solid rgba(224, 225, 236, 1); 33 | border-radius: 6px; 34 | padding-left: 10px; 35 | padding-right: 6px; 36 | 37 | &:hover, 38 | &:focus { 39 | outline: none !important; 40 | border: 1px solid $theme-color !important; 41 | box-shadow: none; 42 | } 43 | } 44 | 45 | .item-num-span { 46 | flex: 1; 47 | text-align: right; 48 | padding-right: 16px; 49 | font-size: 16px; 50 | font-weight: 500; 51 | color: rgba(67, 73, 118, 1); 52 | } 53 | 54 | .item-right-value { 55 | width: 440px; 56 | 57 | .item-right-value-span { 58 | display: block; 59 | font-size: 16px; 60 | font-weight: 500; 61 | color: rgba(67, 73, 118, 1); 62 | } 63 | } 64 | } 65 | 66 | .item-msg { 67 | display: flex; 68 | justify-content: space-between; 69 | margin-top: 16px; 70 | 71 | .item-num-span { 72 | flex: 1; 73 | text-align: right; 74 | padding-right: 16px; 75 | font-size: 16px; 76 | font-weight: 500; 77 | color: rgba(67, 73, 118, 1); 78 | } 79 | 80 | .item-right-value { 81 | width: 440px; 82 | display: block; 83 | font-size: 16px; 84 | font-weight: 500; 85 | color: rgba(67, 73, 118, 1); 86 | 87 | .item-right-value1 { 88 | display: inline-block; 89 | width: 180px; 90 | // background-color: red; 91 | } 92 | } 93 | } 94 | 95 | .item-num { 96 | display: flex; 97 | justify-content: space-between; 98 | margin-top: 16px; 99 | 100 | input { 101 | width: 456px; 102 | height: 46px; 103 | background: rgba(255, 255, 255, 1); 104 | border: 1px solid rgba(224, 225, 236, 1); 105 | border-radius: 6px; 106 | padding-left: 10px; 107 | padding-right: 6px; 108 | 109 | &:hover, 110 | &:focus { 111 | border: 1px solid $theme-color !important; 112 | box-shadow: none; 113 | } 114 | } 115 | 116 | span { 117 | flex: 1; 118 | text-align: right; 119 | padding-right: 16px; 120 | font-size: 16px; 121 | font-weight: 500; 122 | color: rgba(67, 73, 118, 1); 123 | padding-top: 10px; 124 | } 125 | } 126 | 127 | .item-btn-wrap { 128 | text-align: center; 129 | margin-top: 30px; 130 | 131 | button { 132 | width: 110px; 133 | height: 44px; 134 | background: rgba(186, 89, 255, 1); 135 | border-radius: 6px; 136 | color: #fff; 137 | } 138 | } -------------------------------------------------------------------------------- /web-dapp/src/style/tips.scss: -------------------------------------------------------------------------------- 1 | // @media screen and (min-width: 768px) { 2 | 3 | .title { 4 | // font-size: 18px; 5 | font-weight: bold; 6 | color: rgba(67, 73, 118, 1); 7 | // line-height: 60px; 8 | text-align: center; 9 | } 10 | 11 | .wallets { 12 | width: 280px; 13 | margin: 0 auto; 14 | 15 | &__item { 16 | width: 280px; 17 | height: 58px; 18 | background: rgba(255, 255, 255, 1); 19 | border: 1px solid rgba(219, 221, 236, 1); 20 | border-radius: 8px; 21 | margin-bottom: 12px; 22 | display: flex; 23 | justify-content: space-between; 24 | 25 | &:hover { 26 | border: 1px solid #748ffc; 27 | cursor: pointer; 28 | } 29 | 30 | &_name { 31 | font-size: 16px; 32 | font-weight: 400; 33 | color: rgba(67, 73, 118, 1); 34 | line-height: 58px; 35 | padding-left: 20px; 36 | } 37 | 38 | &_icon { 39 | padding-right: 20px; 40 | padding-top: 15px; 41 | 42 | img { 43 | width: 25px; 44 | } 45 | } 46 | } 47 | } 48 | 49 | // } --------------------------------------------------------------------------------