├── test
├── .gitkeep
├── test-tokens
│ ├── truffle.js
│ ├── migrations
│ │ ├── 1_initial_migration.js
│ │ ├── util
│ │ │ └── migrationUtils.js
│ │ ├── 3_deploy_OMG.js
│ │ ├── 2_deploy_RDN.js
│ │ ├── 5_deploy_GRID,CVC.js
│ │ └── 4_deploy_DAI,GEN,KNC,MKR.js
│ ├── contracts
│ │ ├── TokenCVC.sol
│ │ ├── TokenOMG.sol
│ │ ├── TokenRDN.sol
│ │ ├── TokenDAI.sol
│ │ ├── TokenGEN.sol
│ │ ├── TokenKNC.sol
│ │ ├── TokenMKR.sol
│ │ ├── TokenGRID.sol
│ │ ├── Migrations.sol
│ │ └── TestToken.sol
│ ├── README.md
│ ├── src
│ │ ├── inject_network_info.js
│ │ ├── extract_network_info.js
│ │ └── conf
│ │ │ └── network-restore.js
│ ├── package.json
│ └── networks.json
├── resources
│ ├── add-token-pair
│ │ ├── kovan
│ │ │ ├── 01_RDN-WETH.js
│ │ │ ├── WETH_GNO.js
│ │ │ ├── WETH_RDN.js
│ │ │ └── RDN_OMG.js
│ │ ├── mainnet
│ │ │ ├── 01_RDN-WETH.js
│ │ │ ├── 02_OMG-WETH.js
│ │ │ ├── 03_dxDao.js
│ │ │ ├── WETH_GNO.js
│ │ │ ├── WETH_OMG.js
│ │ │ └── WETH_RDN.js
│ │ └── rinkeby
│ │ │ ├── WETH_CVC.js
│ │ │ ├── WETH_GRID.js
│ │ │ ├── WETH_OMG.js
│ │ │ ├── WETH_RDN.js
│ │ │ └── RDN_OMG.js
│ └── approve-tokens
│ │ ├── rdnAndOmg-mainnet.js
│ │ └── rdnAndOmg-rinkeby.js
├── trufflescripts
│ ├── snapshot.js
│ ├── get_account_deposits.js
│ ├── get_account_balances.js
│ ├── revert.js
│ ├── deposit.js
│ ├── withdraw.js
│ ├── utils
│ │ └── index.js
│ ├── give_tokens.js
│ ├── topup_accounts.js
│ ├── buy_order.js
│ ├── sell_order.js
│ ├── claim_funds.js
│ ├── deposit_and_sell.js
│ ├── add_token_pair.js
│ └── increase_time.js
├── dutchExchange-depositWithdrawBadToken.js
├── dutchExchange-DepositAndSell.spec.js
├── dutchExchange-priceOracle.spec.js
├── dutchExchange-getCurrentAuctionPrice.spec.js
├── dutchExchange-TokenApproval.spec.js
├── dutchExchange-UpdateExchangeParams.spec.js
└── dutchExchange-Proxy.spec.js
├── .nvmrc
├── .soliumignore
├── .eslintignore
├── .prettierignore
├── docs
├── StateDiagram.png
├── DutchX_Documentation.pdf
├── DutchX_1.0_Audit_Report.pdf
└── DutchX_2.0_Audit_Report.pdf
├── .gitattributes
├── migrations
├── 1_initial_migration.js
├── 5_deploy_DX.js
├── 4_deploy_FRT.js
├── 3_DEV-deploy_price_feed.js
├── 6_setup_DX.js
├── 2_DEV_migrate_dependencies.js
└── 7_set_DX_as_FRT_minter.js
├── contracts
├── Oracle
│ ├── DSThing.sol
│ ├── DSValue.sol
│ ├── DSNote.sol
│ ├── PriceFeed.sol
│ ├── DSAuth.sol
│ ├── PriceOracleInterface.sol
│ ├── Medianizer.sol
│ └── DSMath.sol
├── DutchExchangeProxy.sol
├── .solhint.json
├── ForTestingOnly
│ ├── TokenGNO.sol
│ ├── TokenOMG.sol
│ ├── TokenRDN.sol
│ ├── BadToken.sol
│ ├── InternalTests.sol
│ └── SubStandardToken.sol
├── Migrations.sol
├── TokenFRTProxy.sol
├── base
│ ├── AuctioneerManaged.sol
│ ├── TokenWhitelist.sol
│ ├── DxUpgrade.sol
│ ├── SafeTransfer.sol
│ ├── EthOracle.sol
│ └── DxMath.sol
├── DxDevDependencies.sol
└── TokenFRT.sol
├── .eslintrc.js
├── .env.example
├── .env
├── src
├── inject_network_info.js
├── extract_network_info.js
├── conf
│ └── network-restore.js
├── inject_network_info_deps_gno.js
├── inject_network_info_deps_utils.js
├── migrations-truffle-4
│ ├── 5_deploy_DX.js
│ ├── 7_set_DX_as_FRT_minter.js
│ ├── index.js
│ ├── 2_migrate_dependencies.js
│ ├── 4_deploy_FRT.js
│ ├── EXAMPLE_migrate_all.js
│ ├── 3_deploy_price_feed.js
│ └── 6_setup_DX.js
├── migrations-truffle-5
│ ├── 5_deploy_DX.js
│ ├── index.js
│ ├── 7_set_DX_as_FRT_minter.js
│ ├── 2_migrate_dependencies.js
│ ├── 4_deploy_FRT.js
│ ├── EXAMPLE_migrate_all.js
│ ├── 3_deploy_price_feed.js
│ └── 6_setup_DX.js
└── truffle
│ ├── get-abi-encoded-params.js
│ ├── unlock-mgn.js
│ ├── set-auctioneer.js
│ ├── wrap-eth.js
│ ├── set-weth-allowance.js
│ ├── deposit-weth.js
│ └── claim-unlocked-mgn.js
├── .npmignore
├── .soliumrc.json
├── travscripts
├── AfterScript.sh
└── BranchScript.sh
├── .gitignore
├── scripts
├── extract_network_info.js
├── inject_network_info.js
└── extractTopTokensEtherscanWeb.js
├── .solcover.js
├── .travis.yml
├── truffle.js
├── package.json
├── deploy-mainnet.txt
├── deploy-kovan.txt
└── deploy-rinkeby.txt
/test/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | v8.1.0
2 |
--------------------------------------------------------------------------------
/.soliumignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | docs
3 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | build
2 | contracts
3 | .*
4 | node_modules
5 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | .history
2 | docs
3 | scripts
4 | migrations
5 | travscripts
--------------------------------------------------------------------------------
/docs/StateDiagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnosis/dx-contracts/HEAD/docs/StateDiagram.png
--------------------------------------------------------------------------------
/docs/DutchX_Documentation.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnosis/dx-contracts/HEAD/docs/DutchX_Documentation.pdf
--------------------------------------------------------------------------------
/test/test-tokens/truffle.js:
--------------------------------------------------------------------------------
1 | const truffleConfig = require('../../truffle')
2 |
3 | module.exports = truffleConfig
--------------------------------------------------------------------------------
/docs/DutchX_1.0_Audit_Report.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnosis/dx-contracts/HEAD/docs/DutchX_1.0_Audit_Report.pdf
--------------------------------------------------------------------------------
/docs/DutchX_2.0_Audit_Report.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnosis/dx-contracts/HEAD/docs/DutchX_2.0_Audit_Report.pdf
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set the default behavior, in case people don't have core.autocrlf set.
2 | *.pdf -diff
3 | *.sol linguist-language=Solidity
4 | #* text eol=lf
--------------------------------------------------------------------------------
/test/resources/add-token-pair/kovan/01_RDN-WETH.js:
--------------------------------------------------------------------------------
1 | // This file can be either JSON, or a JS exporting an object
2 |
3 | module.exports = [
4 | // WETH-RDN
5 | require('./WETH_RDN.js')
6 | ]
--------------------------------------------------------------------------------
/test/resources/add-token-pair/mainnet/01_RDN-WETH.js:
--------------------------------------------------------------------------------
1 | // This file can be either JSON, or a JS exporting an object
2 |
3 | module.exports = [
4 | // WETH-RDN
5 | require('./WETH_RDN.js')
6 | ]
7 |
--------------------------------------------------------------------------------
/test/resources/add-token-pair/mainnet/02_OMG-WETH.js:
--------------------------------------------------------------------------------
1 | // This file can be either JSON, or a JS exporting an object
2 |
3 | module.exports = [
4 | // WETH-OMG
5 | require('./WETH_OMG.js')
6 | ]
7 |
--------------------------------------------------------------------------------
/migrations/1_initial_migration.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | const Migrations = artifacts.require("Migrations");
4 |
5 | module.exports = function(deployer) {
6 | deployer.deploy(Migrations);
7 | };
8 |
--------------------------------------------------------------------------------
/contracts/Oracle/DSThing.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "../Oracle/DSMath.sol";
4 | import "../Oracle/DSAuth.sol";
5 | import "../Oracle/DSNote.sol";
6 |
7 |
8 | contract DSThing is DSAuth, DSNote, DSMath {}
9 |
--------------------------------------------------------------------------------
/test/test-tokens/migrations/1_initial_migration.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | const Migrations = artifacts.require("Migrations");
4 |
5 | module.exports = function(deployer) {
6 | deployer.deploy(Migrations);
7 | };
8 |
--------------------------------------------------------------------------------
/test/test-tokens/contracts/TokenCVC.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "./TestToken.sol";
4 |
5 | contract TokenCVC is TestToken {
6 | constructor(uint amount) public TestToken("CVC", "Civic", 8, amount) {}
7 | }
8 |
--------------------------------------------------------------------------------
/test/test-tokens/contracts/TokenOMG.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "./TestToken.sol";
4 |
5 | contract TokenOMG is TestToken {
6 | constructor(uint amount) public TestToken("OMG", "OmiseGO", 18, amount) {}
7 | }
8 |
--------------------------------------------------------------------------------
/test/test-tokens/contracts/TokenRDN.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "./TestToken.sol";
4 |
5 | contract TokenRDN is TestToken {
6 | constructor(uint amount) public TestToken("RDN", "Raiden", 18, amount) {}
7 | }
8 |
--------------------------------------------------------------------------------
/test/test-tokens/contracts/TokenDAI.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "./TestToken.sol";
4 |
5 | contract TokenDAI is TestToken {
6 | constructor(uint amount) public TestToken("testDAI", "Test DAI", 18, amount) {}
7 | }
8 |
--------------------------------------------------------------------------------
/test/test-tokens/contracts/TokenGEN.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "./TestToken.sol";
4 |
5 | contract TokenGEN is TestToken {
6 | constructor(uint amount) public TestToken("testGEN", "Test GEN", 18, amount) {}
7 | }
8 |
--------------------------------------------------------------------------------
/test/test-tokens/contracts/TokenKNC.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "./TestToken.sol";
4 |
5 | contract TokenKNC is TestToken {
6 | constructor(uint amount) public TestToken("testKNC", "Test KNC", 18, amount) {}
7 | }
8 |
--------------------------------------------------------------------------------
/test/test-tokens/contracts/TokenMKR.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "./TestToken.sol";
4 |
5 | contract TokenMKR is TestToken {
6 | constructor(uint amount) public TestToken("testMKR", "Test MKR", 18, amount) {}
7 | }
8 |
--------------------------------------------------------------------------------
/test/test-tokens/contracts/TokenGRID.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "./TestToken.sol";
4 |
5 | contract TokenGRID is TestToken {
6 | constructor(uint amount) public TestToken("GRID", "GRID Token", 12, amount) {}
7 | }
8 |
--------------------------------------------------------------------------------
/test/resources/add-token-pair/mainnet/03_dxDao.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | // WETH-RDN
3 | // require('./WETH_OMG.js')
4 |
5 | // WETH-RDN
6 | require('./WETH_RDN.js')
7 |
8 | // RDN-OMG
9 | // require('./RDN_OMG.js')
10 | ]
11 |
--------------------------------------------------------------------------------
/contracts/DutchExchangeProxy.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "@gnosis.pm/util-contracts/contracts/Proxy.sol";
4 |
5 |
6 | contract DutchExchangeProxy is Proxy {
7 | constructor(address _masterCopy) public Proxy(_masterCopy) {}
8 | }
9 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: 'standard',
3 | plugins: [],
4 | rules: {
5 | 'strict': 0,
6 | 'arrow-parens': [2, 'as-needed']
7 | },
8 | env: {
9 | 'es6': true,
10 | 'node': true,
11 | 'mocha': true
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/test/test-tokens/README.md:
--------------------------------------------------------------------------------
1 | # Rinkeby test tokens
2 | Just a small truffle project to deploy test tokens for testing in rinkeby.
3 |
4 | # Install dependencies
5 | ```bash
6 | yarn install
7 | ```
8 |
9 | # Deploy in rinkeby
10 | ```bash
11 | yarn migrate --network rinkeby
12 | ```
13 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | # Mnemonic or MNEMONIC
2 | #MNEMONIC='your mnemonic here'
3 | #PK='your-private-key'
4 |
5 | # Gas Price
6 | # GAS_PRICE_GWEI=4
7 |
8 | # Allow to use native solc docker image
9 | # - Requires to have the image:
10 | # docker pull ethereum/solc:0.4.25
11 | SOLC_USE_DOCKER=false
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | # Mnemonic or MNEMONIC
2 | #MNEMONIC='your mnemonic here'
3 | #PK='your-private-key'
4 |
5 | # Gas Price
6 | # GAS_PRICE_GWEI=4
7 |
8 | # Allow to use native solc docker image
9 | # - Requires to have the image:
10 | # docker pull ethereum/solc:0.4.25
11 | # docker pull ethereum/solc:0.5.0
12 | SOLC_USE_DOCKER=true
--------------------------------------------------------------------------------
/test/test-tokens/migrations/util/migrationUtils.js:
--------------------------------------------------------------------------------
1 | module.exports = ({ web3 }) => {
2 | const BN = web3.utils.BN
3 |
4 | return {
5 | toWei (amount, decimals = 18) {
6 | const expoential = new BN(Math.pow(10, decimals).toString())
7 | return (new BN(amount)).mul(expoential).toString()
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/inject_network_info.js:
--------------------------------------------------------------------------------
1 | const injectNetworks = require('@gnosis.pm/util-contracts/src/util/injectNetworks')
2 | const path = require('path')
3 |
4 | const DEFAULT_CONF_FILE = path.join(__dirname, './conf/network-restore')
5 |
6 | const confFile = process.env.CONF_FILE || DEFAULT_CONF_FILE
7 | injectNetworks(confFile)
8 | .catch(console.error)
9 |
--------------------------------------------------------------------------------
/src/extract_network_info.js:
--------------------------------------------------------------------------------
1 | const extractNetworks = require('@gnosis.pm/util-contracts/src/util/extractNetworks')
2 | const path = require('path')
3 |
4 | const DEFAULT_CONF_FILE = path.join(__dirname, './conf/network-restore')
5 |
6 | const confFile = process.env.CONF_FILE || DEFAULT_CONF_FILE
7 | extractNetworks(confFile)
8 | .catch(console.error)
9 |
--------------------------------------------------------------------------------
/test/test-tokens/src/inject_network_info.js:
--------------------------------------------------------------------------------
1 | const injectNetworks = require('@gnosis.pm/util-contracts/src/util/injectNetworks')
2 | const path = require('path')
3 |
4 | const DEFAULT_CONF_FILE = path.join(__dirname, './conf/network-restore')
5 |
6 | const confFile = process.env.CONF_FILE || DEFAULT_CONF_FILE
7 | injectNetworks(confFile)
8 | .catch(console.error)
9 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_STORE
2 | .history
3 |
4 | migrations/4_deploy_internalTestContracts.js
5 | scripts/startAuctionTruffleScript.js
6 | scripts/listOfTOP150TokensByMarketCap.txt
7 | travscripts/*
8 | .gitattributes
9 | .solcover.js
10 | .travis.yml
11 | *.pyc
12 | yarn-error.log
13 |
14 | records.json
15 | stats.json
16 | .awcache
17 | .eslintcache
18 | .stylelintcache
--------------------------------------------------------------------------------
/migrations/5_deploy_DX.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 |
4 | const deployDx = require('../src/migrations-truffle-5/5_deploy_DX')
5 |
6 | module.exports = function (deployer, network, accounts) {
7 | return deployDx({
8 | artifacts,
9 | deployer,
10 | network,
11 | accounts,
12 | web3
13 | })
14 | }
15 |
--------------------------------------------------------------------------------
/test/test-tokens/src/extract_network_info.js:
--------------------------------------------------------------------------------
1 | const extractNetworks = require('@gnosis.pm/util-contracts/src/util/extractNetworks')
2 | const path = require('path')
3 |
4 | const DEFAULT_CONF_FILE = path.join(__dirname, './conf/network-restore')
5 |
6 | const confFile = process.env.CONF_FILE || DEFAULT_CONF_FILE
7 | extractNetworks(confFile)
8 | .catch(console.error)
9 |
--------------------------------------------------------------------------------
/migrations/4_deploy_FRT.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 |
4 | const deployFrt = require('../src/migrations-truffle-5/4_deploy_FRT')
5 |
6 | module.exports = function (deployer, network, accounts) {
7 | return deployFrt({
8 | artifacts,
9 | deployer,
10 | network,
11 | accounts,
12 | web3
13 | })
14 | }
15 |
--------------------------------------------------------------------------------
/src/conf/network-restore.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | const BASE_DIR = path.join(__dirname, '../..')
4 | const BUILD_DIR = path.join(BASE_DIR, 'build/contracts')
5 | const NETWORKS_FILE_PATH = path.join(BASE_DIR, 'networks.json')
6 |
7 | module.exports = {
8 | buildPath: BUILD_DIR,
9 | networkFilePath: NETWORKS_FILE_PATH,
10 | buildDirDependencies: []
11 | }
12 |
--------------------------------------------------------------------------------
/test/test-tokens/src/conf/network-restore.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | const BASE_DIR = path.join(__dirname, '../..')
4 | const BUILD_DIR = path.join(BASE_DIR, 'build/contracts')
5 | const NETWORKS_FILE_PATH = path.join(BASE_DIR, 'networks.json')
6 |
7 | module.exports = {
8 | buildPath: BUILD_DIR,
9 | networkFilePath: NETWORKS_FILE_PATH,
10 | buildDirDependencies: []
11 | }
12 |
--------------------------------------------------------------------------------
/.soliumrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "solium:all",
3 | "plugins": [
4 | "security"
5 | ],
6 | "rules": {
7 | "quotes": [
8 | "error",
9 | "double"
10 | ],
11 | "indentation": [
12 | "error",
13 | 4
14 | ],
15 | "arg-overflow": [
16 | "warning",
17 | 5
18 | ],
19 | "error-reason": 0,
20 | "security/no-assign-params": 0
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/travscripts/AfterScript.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #if [[ $TRAVIS_BRANCH =~ (feature/test-?(\/[a-zA-Z0-9/._-]*)?) ]]; then
4 | echo " ==> Detected a CONTRACT(S) branch"
5 | #jump back to root
6 | cd $TRAVIS_BUILD_DIR
7 | echo " ==> JUMPING LOCATIONS: NOW IN $TRAVIS_BUILD_DIR"
8 | #run solcover
9 | echo " ==> RUNNING solidity-coverage" &&
10 |
11 | npm run coverage && cat ./coverage/lcov.info | coveralls
12 | #fi;
13 |
--------------------------------------------------------------------------------
/src/inject_network_info_deps_gno.js:
--------------------------------------------------------------------------------
1 | const injectNetworksDeps = require('@gnosis.pm/util-contracts/src/util/injectNetworksDeps')
2 | const path = require('path')
3 |
4 | const NODE_MODULES_PATH = path.join(__dirname, '../node_modules')
5 |
6 | injectNetworksDeps({
7 | buildPath: '@gnosis.pm/gno-token/build/contracts',
8 | packages: [
9 | '@gnosis.pm/owl-token'
10 | ],
11 | nodeModulesPath: NODE_MODULES_PATH
12 | }).catch(console.error)
13 |
--------------------------------------------------------------------------------
/contracts/.solhint.json:
--------------------------------------------------------------------------------
1 | diud{
2 | "extends": "default",
3 | "rules": {
4 | "indent": ["error", 4],
5 | "quotes": ["error", "double"],
6 | "max-line-length": ["error", 129],
7 | "function-max-lines": ["error", 45],
8 | "max-states-count": ["error", 18]
9 | }
10 | }
--------------------------------------------------------------------------------
/contracts/ForTestingOnly/TokenGNO.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "./SubStandardToken.sol";
4 |
5 | contract BadGNO is SubStandardToken {
6 | string public constant symbol = "GNO";
7 | string public constant name = "Gnosis";
8 | uint8 public constant decimals = 18;
9 |
10 | constructor(uint amount)
11 | public
12 | {
13 | totalTokens = amount;
14 | balances[msg.sender] = amount;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/contracts/ForTestingOnly/TokenOMG.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "@gnosis.pm/util-contracts/contracts/GnosisStandardToken.sol";
4 |
5 |
6 | contract TokenOMG is GnosisStandardToken {
7 | string public constant symbol = "OMG";
8 | string public constant name = "OMG Test Token";
9 | uint8 public constant decimals = 18;
10 |
11 | constructor(uint amount) public {
12 | balances[msg.sender] = amount;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/contracts/ForTestingOnly/TokenRDN.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "@gnosis.pm/util-contracts/contracts/GnosisStandardToken.sol";
4 |
5 |
6 | contract TokenRDN is GnosisStandardToken {
7 | string public constant symbol = "RDN";
8 | string public constant name = "Raiden network tokens";
9 | uint8 public constant decimals = 18;
10 |
11 | constructor(uint amount) public {
12 | balances[msg.sender] = amount;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/test/test-tokens/migrations/3_deploy_OMG.js:
--------------------------------------------------------------------------------
1 | /* global web3, artifacts */
2 | /* eslint no-undef: "error" */
3 |
4 | const TokenOMG = artifacts.require('TokenOMG')
5 | const INITIAL_FUNDING = 10e6 // 00M
6 |
7 | const { toWei } = require('./util/migrationUtils')({
8 | web3
9 | })
10 |
11 | module.exports = function (deployer) {
12 | console.log('Deploy OMG with initial funding of: ', INITIAL_FUNDING)
13 | deployer.deploy(TokenOMG, toWei(INITIAL_FUNDING).toString())
14 | }
15 |
--------------------------------------------------------------------------------
/test/test-tokens/migrations/2_deploy_RDN.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 |
4 | const TokenRDN = artifacts.require('TokenRDN')
5 | const INITIAL_FUNDING = 100e6 // 100M
6 |
7 | const { toWei } = require('./util/migrationUtils')({
8 | web3
9 | })
10 |
11 | module.exports = function (deployer) {
12 | console.log('Deploy RDN with initial funding of: ', INITIAL_FUNDING)
13 | deployer.deploy(TokenRDN, toWei(INITIAL_FUNDING).toString())
14 | }
15 |
--------------------------------------------------------------------------------
/src/inject_network_info_deps_utils.js:
--------------------------------------------------------------------------------
1 | const injectNetworksDeps = require('@gnosis.pm/util-contracts/src/util/injectNetworksDeps')
2 | const path = require('path')
3 |
4 | const NODE_MODULES_PATH = path.join(__dirname, '../node_modules')
5 |
6 | injectNetworksDeps({
7 | buildPath: '@gnosis.pm/util-contracts/build/contracts',
8 | packages: [
9 | '@gnosis.pm/gno-token',
10 | '@gnosis.pm/owl-token'
11 | ],
12 | nodeModulesPath: NODE_MODULES_PATH
13 | }).catch(console.error)
14 |
--------------------------------------------------------------------------------
/migrations/3_DEV-deploy_price_feed.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 | const deployPriceFeed = require('../src/migrations-truffle-5/3_deploy_price_feed')
4 |
5 | module.exports = function (deployer, network, accounts) {
6 | return deployPriceFeed({
7 | artifacts,
8 | deployer,
9 | network,
10 | accounts,
11 | web3,
12 | ethUsdPrice: process.env.ETH_USD_PRICE,
13 | feedExpirePeriodDays: process.env.FEED_EXPIRE_PERIOD_DAYS
14 | })
15 | }
16 |
--------------------------------------------------------------------------------
/migrations/6_setup_DX.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 | const setupDx = require('../src/migrations-truffle-5/6_setup_DX')
4 |
5 | module.exports = function (deployer, network, accounts) {
6 | return setupDx({
7 | artifacts,
8 | deployer,
9 | network,
10 | accounts,
11 | web3,
12 | thresholdNewTokenPairUsd: process.env.THRESHOLD_NEW_TOKEN_PAIR_USD,
13 | thresholdAuctionStartUsd: process.env.THRESHOLD_AUCTION_START_USD
14 | })
15 | }
16 |
--------------------------------------------------------------------------------
/src/migrations-truffle-4/5_deploy_DX.js:
--------------------------------------------------------------------------------
1 | function migrate ({
2 | artifacts,
3 | deployer,
4 | network,
5 | accounts
6 | }) {
7 | const DutchExchange = artifacts.require('DutchExchange')
8 | const DutchExchangeProxy = artifacts.require('DutchExchangeProxy')
9 |
10 | return deployer
11 | // Deploy DX and it's proxy
12 | .then(() => deployer.deploy(DutchExchange))
13 | .then(() => deployer.deploy(DutchExchangeProxy, DutchExchange.address))
14 | }
15 |
16 | module.exports = migrate
17 |
--------------------------------------------------------------------------------
/src/migrations-truffle-4/7_set_DX_as_FRT_minter.js:
--------------------------------------------------------------------------------
1 | function migrate ({
2 | artifacts,
3 | deployer
4 | }) {
5 | const TokenFRT = artifacts.require('TokenFRT')
6 | const TokenFRTProxy = artifacts.require('TokenFRTProxy')
7 | const DutchExchangeProxy = artifacts.require('DutchExchangeProxy')
8 |
9 | return deployer
10 | .then(() => TokenFRT.at(TokenFRTProxy.address))
11 | .then(tokenFRT => tokenFRT.updateMinter(DutchExchangeProxy.address))
12 | }
13 |
14 | module.exports = migrate
15 |
--------------------------------------------------------------------------------
/test/trufflescripts/snapshot.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | const { makeSnapshot } = require('./utils')(web3)
3 |
4 | /**
5 | * truffle exec test/trufflescripts/snapshot.js
6 | * Created snapshot of blockchain state and assigns a Block-ID
7 | * Block-ID can be reverted back to via revert.js
8 | */
9 |
10 | module.exports = () => {
11 | const snapshot = makeSnapshot()
12 | console.log(`
13 | SNAPSHOT CREATED: # ${snapshot}
14 | BLOCK-NUMBER: ${web3.eth.blockNumber}
15 | `)
16 | }
17 |
--------------------------------------------------------------------------------
/src/migrations-truffle-5/5_deploy_DX.js:
--------------------------------------------------------------------------------
1 | async function migrate ({
2 | artifacts,
3 | deployer
4 | }) {
5 | const DutchExchange = artifacts.require('DutchExchange')
6 | const DutchExchangeProxy = artifacts.require('DutchExchangeProxy')
7 |
8 | console.log('Deploy DutchExchange contract')
9 | await deployer.deploy(DutchExchange)
10 |
11 | console.log('Deploy DutchExchangeProxy contract')
12 | await deployer.deploy(DutchExchangeProxy, DutchExchange.address)
13 | }
14 |
15 | module.exports = migrate
16 |
--------------------------------------------------------------------------------
/migrations/2_DEV_migrate_dependencies.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 | const migrateDependencies = require('../src/migrations-truffle-5/2_migrate_dependencies')
4 |
5 | module.exports = function (deployer, network, accounts) {
6 | return migrateDependencies({
7 | artifacts,
8 | deployer,
9 | network,
10 | accounts,
11 | web3,
12 | ethUsdPrice: process.env.ETH_USD_PRICE,
13 | feedExpirePeriodDays: process.env.FEED_EXPIRE_PERIOD_DAYS
14 | })
15 | }
16 |
--------------------------------------------------------------------------------
/src/migrations-truffle-5/index.js:
--------------------------------------------------------------------------------
1 | const migrateDependencies = require('./2_migrate_dependencies')
2 | const deployPriceFeed = require('./3_deploy_price_feed')
3 | const deployFRT = require('./4_deploy_FRT')
4 | const deployDX = require('./5_deploy_DX')
5 | const setupDx = require('./6_setup_DX')
6 | const setDxAsFrtMintern = require('./7_set_DX_as_FRT_minter')
7 |
8 | module.exports = async params => {
9 | await migrateDependencies(params)
10 | await deployPriceFeed(params)
11 | await deployFRT(params)
12 | await deployDX(params)
13 | await setupDx(params)
14 | await setDxAsFrtMintern(params)
15 | }
16 |
--------------------------------------------------------------------------------
/travscripts/BranchScript.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function run_tests {
4 | #jump back to root
5 | cd $TRAVIS_BUILD_DIR
6 | echo " ==> JUMPING LOCATIONS: NOW IN $TRAVIS_BUILD_DIR"
7 |
8 | # running contracts tests
9 | echo " ==> RUNNING test"
10 | npm test;
11 | }
12 |
13 | if [[ $TRAVIS_BRANCH = "master" || $TRAVIS_BRANCH = "develop" ]]; then
14 | echo " ==> Detected PRINCIPAL branch - compiling and testing contracts"
15 | run_tests
16 | else
17 | # echo " ==> No execution for branches other than MASTER or DEVELOP"
18 | echo " ==> Detected BRANCH branch - compiling and testing contracts"
19 | run_tests
20 | fi;
21 |
--------------------------------------------------------------------------------
/migrations/7_set_DX_as_FRT_minter.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 | const setDxAsFrtOwner = require('../src/migrations-truffle-5/7_set_DX_as_FRT_minter')
4 |
5 | module.exports = function (deployer, network, accounts) {
6 | return setDxAsFrtOwner({
7 | artifacts,
8 | deployer,
9 | network,
10 | accounts,
11 | web3
12 | })
13 | }
14 | // Last step of the migration:
15 |
16 | // At some later point we would change the ownerShip of the MagnoliaTokens in order to make funds secure. See audit report
17 | // .then(() => TokenFRT.deployed())
18 | // .then(T => T.updateOwner(Proxy.address))
19 |
--------------------------------------------------------------------------------
/test/test-tokens/migrations/5_deploy_GRID,CVC.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 |
4 | const { toWei } = require('./util/migrationUtils')({
5 | web3
6 | })
7 |
8 | const INITIAL_FUNDING = 10e6 // 10M
9 | module.exports = function (deployer) {
10 | function _deploy (token, decimals) {
11 | console.log('Deploy %s with initial funding of: %s', token, INITIAL_FUNDING)
12 |
13 | return deployer
14 | .deploy(artifacts.require(`Token${token}`), toWei(INITIAL_FUNDING, decimals))
15 | }
16 |
17 | deployer
18 | .then(() => _deploy('GRID', 12))
19 | .then(() => _deploy('CVC', 8))
20 | }
21 |
--------------------------------------------------------------------------------
/test/test-tokens/contracts/Migrations.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | contract Migrations {
4 | address public owner;
5 | uint 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(uint completed) public restricted {
16 | last_completed_migration = completed;
17 | }
18 |
19 | function upgrade(address new_address) public restricted {
20 | Migrations upgraded = Migrations(new_address);
21 | upgraded.setCompleted(last_completed_migration);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .DS_STORE
3 | node_modules
4 | *~
5 | *.pyc
6 | static
7 | .grunt
8 | _SpecRunner.html
9 | __benchmarks__
10 | dist/
11 | build/
12 | coverage/
13 | .module-cache
14 | *.gem
15 | docs/.bundle
16 | docs/code
17 | docs/_site
18 | docs/.sass-cache
19 | docs/js/*
20 | docs/downloads/*.zip
21 | docs/vendor/bundle
22 | examples/shared/*.js
23 | examples/**/bundle.js
24 | test/the-files-to-test.generated.js
25 | *.log*
26 | chrome-user-data
27 | *.sublime-project
28 | *.sublime-workspace
29 | .idea
30 | *.iml
31 | .vscode
32 | /semantic.json
33 | /semantic
34 | yarn-error.log
35 |
36 | records.json
37 | stats.json
38 | .awcache
39 | .eslintcache
40 | .stylelintcache
41 | .history
42 |
--------------------------------------------------------------------------------
/contracts/Migrations.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 |
4 | contract Migrations {
5 | address public owner;
6 | uint public last_completed_migration;
7 |
8 | modifier restricted() {
9 | if (msg.sender == owner)
10 | _;
11 | }
12 |
13 | constructor() public {
14 | owner = msg.sender;
15 | }
16 |
17 | function setCompleted(uint completed) public restricted {
18 | last_completed_migration = completed;
19 | }
20 |
21 | function upgrade(address new_address) public restricted {
22 | Migrations upgraded = Migrations(new_address);
23 | upgraded.setCompleted(last_completed_migration);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/migrations-truffle-4/index.js:
--------------------------------------------------------------------------------
1 | const migrateDependencies = require('./2_migrate_dependencies')
2 | const deployPriceFeed = require('./3_deploy_price_feed')
3 | const deployFRT = require('./4_deploy_FRT')
4 | const deployDX = require('./5_deploy_DX')
5 | const setupDx = require('./6_setup_DX')
6 | const setDxAsFrtMintern = require('./7_set_DX_as_FRT_minter')
7 |
8 | module.exports = params => {
9 | return params.deployer
10 | .then(() => migrateDependencies(params))
11 | .then(() => deployPriceFeed(params))
12 | .then(() => deployFRT(params))
13 | .then(() => deployDX(params))
14 | .then(() => setupDx(params))
15 | .then(() => setDxAsFrtMintern(params))
16 | }
17 |
--------------------------------------------------------------------------------
/test/test-tokens/migrations/4_deploy_DAI,GEN,KNC,MKR.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 |
4 | const INITIAL_FUNDING = 10e6 // 10M
5 | const { toWei } = require('./util/migrationUtils')({
6 | web3
7 | })
8 |
9 | module.exports = function (deployer) {
10 | function _deploy (token) {
11 | console.log('Deploy %s with initial funding of: %s', token, INITIAL_FUNDING)
12 |
13 | return deployer
14 | .deploy(artifacts.require(`Token${token}`), toWei(INITIAL_FUNDING))
15 | }
16 |
17 | deployer
18 | .then(() => _deploy('DAI'))
19 | .then(() => _deploy('GEN'))
20 | .then(() => _deploy('KNC'))
21 | .then(() => _deploy('MKR'))
22 | }
23 |
--------------------------------------------------------------------------------
/test/resources/add-token-pair/kovan/WETH_GNO.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // WETH
3 | tokenA: {
4 | symbol: 'WETH',
5 | address: '0xd0a1e359811322d97991e03f863a0c30c2cf029c',
6 | // Check ETH oracle:
7 | // https://makerdao.com/feeds/#0x729d19f657bd0614b4985cf1d82531c67569197b
8 | // Price: 205
9 | // 1000$ = 1000/205 = 4.87
10 | funding: 5
11 | },
12 | // GNO
13 | tokenB: {
14 | symbol: 'GNO',
15 | address: '0x6018bf616ec9db02f90c8c8529ddadc10a5c29dc',
16 | funding: 0
17 | },
18 | // Price:
19 | // 1 ETH = 10 GNO
20 | // initial price = 859 RDN/WETH
21 | initialPrice: {
22 | numerator: 10,
23 | denominator: 1
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/contracts/Oracle/DSValue.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "../Oracle/DSThing.sol";
4 |
5 |
6 | contract DSValue is DSThing {
7 | bool has;
8 | bytes32 val;
9 | function peek() public view returns (bytes32, bool) {
10 | return (val, has);
11 | }
12 |
13 | function read() public view returns (bytes32) {
14 | (bytes32 wut, bool _has) = peek();
15 | assert(_has);
16 | return wut;
17 | }
18 |
19 | function poke(bytes32 wut) public payable note auth {
20 | val = wut;
21 | has = true;
22 | }
23 |
24 | function void() public payable note auth {
25 | // unset the value
26 | has = false;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/contracts/TokenFRTProxy.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "@gnosis.pm/util-contracts/contracts/Proxy.sol";
4 | import "@gnosis.pm/util-contracts/contracts/GnosisStandardToken.sol";
5 |
6 |
7 | contract TokenFRTProxy is Proxy, GnosisStandardToken {
8 | /// @dev State variables remain for Blockchain exploring Proxied Token contracts
9 | address public owner;
10 |
11 | string public constant symbol = "MGN";
12 | string public constant name = "Magnolia Token";
13 | uint8 public constant decimals = 18;
14 |
15 | constructor(address proxied, address _owner) public Proxy(proxied) {
16 | require(_owner != address(0), "owner address cannot be 0");
17 | owner = _owner;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/migrations-truffle-5/7_set_DX_as_FRT_minter.js:
--------------------------------------------------------------------------------
1 | async function migrate ({
2 | artifacts
3 | }) {
4 | const TokenFRT = artifacts.require('TokenFRT')
5 | const TokenFRTProxy = artifacts.require('TokenFRTProxy')
6 | const DutchExchangeProxy = artifacts.require('DutchExchangeProxy')
7 |
8 | // Make sure TokenFRT and the proxy are deployed
9 | const dxProxy = await DutchExchangeProxy.deployed()
10 | const frtProxy = await TokenFRTProxy.deployed()
11 | const tokenFrt = await TokenFRT.at(frtProxy.address)
12 |
13 | console.log('Update minter in TokenFRT:')
14 | console.log(' - Set dutchX address: %s', dxProxy.address)
15 | await tokenFrt.updateMinter(dxProxy.address)
16 | }
17 |
18 | module.exports = migrate
19 |
--------------------------------------------------------------------------------
/scripts/extract_network_info.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 | const _ = require('lodash')
4 |
5 | const dir = path.join('build', 'contracts')
6 | const dirFiles = fs.readdirSync(dir)
7 | const networkFile = process.env.NETWORKS_FILE || 'networks.json'
8 |
9 | Promise.all(dirFiles.filter(fname => fname.endsWith('.json')).map(fname => new Promise((resolve, reject) => {
10 | fs.readFile(path.join(dir, fname), (err, data) => {
11 | if (err) throw err
12 | resolve([fname.slice(0, -5), JSON.parse(data)['networks']])
13 | })
14 | }))).then(nameNetworkPairs => {
15 | fs.writeFileSync(networkFile, JSON.stringify(_.fromPairs(nameNetworkPairs.filter(([_name, nets]) => !_.isEmpty(nets))), null, 2))
16 | })
17 |
--------------------------------------------------------------------------------
/test/resources/add-token-pair/rinkeby/WETH_CVC.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // WETH
3 | tokenA: {
4 | symbol: 'WETH',
5 | address: '0xc778417e063141139fce010982780140aa0cd5ab',
6 | funding: 5
7 | },
8 | // CVC
9 | tokenB: {
10 | symbol: 'CVC',
11 | address: '0x67Fe0FDf579043de35d9CB2F10C81B63aa8aEef9',
12 | funding: 0
13 | },
14 | // Price:
15 | // https://www.coingecko.com/en/coins/civic?utm_content=civic&utm_medium=search_coin&utm_source=coingecko
16 | // 1 ETH = 3176 CVC
17 | // 1 * 1e18 ETH in wei = 3176 * 1e8 CVC in wei
18 | // Price = (3176 * 1e8) / (1 * 1e18)
19 | // Price = 3176 / (1 * 1e10)
20 |
21 | initialPrice: {
22 | numerator: 3176,
23 | denominator: 1e10
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/test/resources/add-token-pair/rinkeby/WETH_GRID.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // WETH
3 | tokenA: {
4 | symbol: 'WETH',
5 | address: '0xc778417e063141139fce010982780140aa0cd5ab',
6 | funding: 5
7 | },
8 | // CVC
9 | tokenB: {
10 | symbol: 'GRID',
11 | address: '0xB35E3E3E7A87C2B04DEc49a7b5DA7c1A23a09e64',
12 | funding: 0
13 | },
14 | // Price:
15 | // https://www.coingecko.com/en/coins/grid?utm_content=grid&utm_medium=search_coin&utm_source=coingecko
16 | // 1 ETH = 1706 GRID
17 | // 1 * 1e18 ETH in wei = 1706 * 1e12 GRID in wei
18 | // Price = (1706 * 1e8) / (1 * 1e18)
19 | // Price = 1706 / (1 * 1e6)
20 |
21 | initialPrice: {
22 | numerator: 1706,
23 | denominator: 1e6
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/contracts/base/AuctioneerManaged.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 |
4 | contract AuctioneerManaged {
5 | // auctioneer has the power to manage some variables
6 | address public auctioneer;
7 |
8 | function updateAuctioneer(address _auctioneer) public onlyAuctioneer {
9 | require(_auctioneer != address(0), "The auctioneer must be a valid address");
10 | auctioneer = _auctioneer;
11 | }
12 |
13 | // > Modifiers
14 | modifier onlyAuctioneer() {
15 | // Only allows auctioneer to proceed
16 | // R1
17 | // require(msg.sender == auctioneer, "Only auctioneer can perform this operation");
18 | require(msg.sender == auctioneer, "Only the auctioneer can nominate a new one");
19 | _;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/test/resources/add-token-pair/rinkeby/WETH_OMG.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // WETH
3 | tokenA: {
4 | symbol: 'WETH',
5 | address: '0xc778417e063141139fce010982780140aa0cd5ab',
6 | // Check ETH oracle:
7 | // https://makerdao.com/feeds/#0x729d19f657bd0614b4985cf1d82531c67569197b
8 | // Price: 500
9 | // 10000$ = 10000/500 ETH = 20
10 | funding: 20
11 | },
12 | // OMG
13 | tokenB: {
14 | symbol: 'OMG',
15 | address: '0x00df91984582e6e96288307e9c2f20b38c8fece9',
16 | funding: 0
17 | },
18 | // Price:
19 | // https://www.coingecko.com/en/price_charts/omisego/eth
20 | // 1 ETH = 97,09644726041404 OMG
21 | // initial price = 98 OMG/WETH
22 | initialPrice: {
23 | numerator: 98,
24 | denominator: 1
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/contracts/Oracle/DSNote.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 |
4 | contract DSNote {
5 | event LogNote(
6 | bytes4 indexed sig,
7 | address indexed guy,
8 | bytes32 indexed foo,
9 | bytes32 bar,
10 | uint wad,
11 | bytes fax
12 | );
13 |
14 | modifier note {
15 | bytes32 foo;
16 | bytes32 bar;
17 | // solium-disable-next-line security/no-inline-assembly
18 | assembly {
19 | foo := calldataload(4)
20 | bar := calldataload(36)
21 | }
22 |
23 | emit LogNote(
24 | msg.sig,
25 | msg.sender,
26 | foo,
27 | bar,
28 | msg.value,
29 | msg.data
30 | );
31 |
32 | _;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/test/resources/add-token-pair/rinkeby/WETH_RDN.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // WETH
3 | tokenA: {
4 | symbol: 'WETH',
5 | address: '0xc778417e063141139fce010982780140aa0cd5ab',
6 | // Check ETH oracle:
7 | // https://makerdao.com/feeds/#0x729d19f657bd0614b4985cf1d82531c67569197b
8 | // Price: 500
9 | // 10000$ = 10000/500 ETH = 20
10 | funding: 20
11 | },
12 | // RDN
13 | tokenB: {
14 | symbol: 'RDN',
15 | address: '0x3615757011112560521536258c1e7325ae3b48ae',
16 | funding: 0
17 | },
18 | // Price:
19 | // https://www.coingecko.com/en/price_charts/raiden-network/eth
20 | // 1 ETH = 511,3250313237714 RDN
21 | // initial price = 512 RDN/WETH
22 | initialPrice: {
23 | numerator: 512,
24 | denominator: 1
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/test/resources/add-token-pair/kovan/WETH_RDN.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // WETH
3 | tokenA: {
4 | symbol: 'WETH',
5 | address: '0xd0a1e359811322d97991e03f863a0c30c2cf029c',
6 | // Check ETH oracle:
7 | // https://makerdao.com/feeds/#0x729d19f657bd0614b4985cf1d82531c67569197b
8 | // Price: 256.493
9 | // 10000$ = 10000/256.493 ETH = 38.98741876
10 | funding: 70
11 | },
12 | // RDN
13 | tokenB: {
14 | symbol: 'RDN',
15 | address: '0x1f7f270df126ba464228cc8d8203d2768429e085',
16 | funding: 0
17 | },
18 | // Price:
19 | // https://www.coingecko.com/en/price_charts/raiden-network/eth
20 | // 1 ETH = 859 RDN
21 | // initial price = 859 RDN/WETH
22 | initialPrice: {
23 | numerator: 859,
24 | denominator: 1
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/test/resources/add-token-pair/mainnet/WETH_GNO.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // WETH
3 | tokenA: {
4 | symbol: 'WETH',
5 | address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
6 | // Check ETH oracle
7 | // https://makerdao.com/feeds/#0x729d19f657bd0614b4985cf1d82531c67569197b
8 | // Price: 133.245
9 | // 10000$ = 10000/133.245 ETH = 75.0497204398
10 | funding: 75.5
11 | },
12 | // GNO
13 | tokenB: {
14 | symbol: 'GNO',
15 | address: '0x6810e776880c02933d47db1b9fc05908e5386b96',
16 | funding: 72
17 | },
18 | // Price:
19 | // https://www.coingecko.com/en/price_charts/gnosis/eth
20 | // 1 ETH = 9,553282765896997 GNO
21 | // initial price = 10 GNO
22 | initialPrice: {
23 | numerator: 10,
24 | denominator: 1
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/test/resources/add-token-pair/mainnet/WETH_OMG.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // WETH
3 | tokenA: {
4 | symbol: 'WETH',
5 | address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
6 | // Check ETH oracle:
7 | // https://makerdao.com/feeds/#0x729d19f657bd0614b4985cf1d82531c67569197b
8 | // Price: 118.995
9 | // 10000$ = 10000/118.995 ETH = 84,0371444178
10 | funding: 88
11 | },
12 | // OMG
13 | tokenB: {
14 | symbol: 'OMG',
15 | address: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07',
16 | funding: 0
17 | },
18 | // Price:
19 | // https://www.coingecko.com/en/price_charts/omisego/eth
20 | // 1 ETH = 105,54353039478472 OMG
21 | // initial price = 65 OMG/WETH
22 | initialPrice: {
23 | numerator: 106,
24 | denominator: 1
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/test/resources/add-token-pair/mainnet/WETH_RDN.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // WETH
3 | tokenA: {
4 | symbol: 'WETH',
5 | address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
6 | // Check ETH oracle
7 | // https://makerdao.com/feeds/#0x729d19f657bd0614b4985cf1d82531c67569197b
8 | // Price: 118.285
9 | // 10000$ = 10000/118.285 ETH = 84.5415733187
10 | funding: 86
11 | },
12 | // RDN
13 | tokenB: {
14 | symbol: 'RDN',
15 | address: '0x255aa6df07540cb5d3d297f0d0d4d84cb52bc8e6',
16 | funding: 0
17 | },
18 | // Price:
19 | // https://www.coingecko.com/en/price_charts/raiden-network/eth
20 | // 1 ETH = 551,0627106609419 RDN
21 | // initial price = 552 RDN/WETH
22 | initialPrice: {
23 | numerator: 552,
24 | denominator: 1
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/scripts/inject_network_info.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 | const _ = require('lodash')
4 |
5 | const dir = path.join('build', 'contracts')
6 | const networkFile = process.env.NETWORKS_FILE || 'networks.json'
7 | const contractNetworksMap = JSON.parse(fs.readFileSync(networkFile))
8 |
9 | _.toPairs(contractNetworksMap)
10 | .map(([name, networks]) => [path.join(dir, name + '.json'), networks])
11 | .filter(([file, _networks]) => {
12 | if (!fs.existsSync(file)) { throw new Error(`missing build artifact ${file}; make sure contracts are compiled`) }
13 | return true
14 | })
15 | .forEach(([file, networks]) => {
16 | const artifactData = JSON.parse(fs.readFileSync(file))
17 | _.merge(artifactData.networks, networks)
18 | fs.writeFileSync(file, JSON.stringify(artifactData, null, 2))
19 | })
20 |
--------------------------------------------------------------------------------
/test/resources/approve-tokens/rdnAndOmg-mainnet.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | 'name': 'Wrapped Ether',
4 | 'symbol': 'WETH',
5 | 'approve': true,
6 | 'etherScanLink': 'https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
7 | 'address': '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'
8 | },
9 | {
10 | 'name': 'OmiseGO',
11 | 'symbol': 'OMG',
12 | 'approve': true,
13 | 'etherScanLink': 'https://etherscan.io/token/0xd26114cd6EE289AccF82350c8d8487fedB8A0C07',
14 | 'address': '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07'
15 | },
16 | {
17 | 'name': 'Raiden',
18 | 'symbol': 'RDN',
19 | 'approve': true,
20 | 'etherScanLink': 'https://etherscan.io/token/0x255aa6df07540cb5d3d297f0d0d4d84cb52bc8e6',
21 | 'address': '0x255aa6df07540cb5d3d297f0d0d4d84cb52bc8e6'
22 | }
23 | ]
24 |
--------------------------------------------------------------------------------
/test/resources/approve-tokens/rdnAndOmg-rinkeby.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | 'name': 'Wrapped Ether',
4 | 'symbol': 'WETH',
5 | 'approve': true,
6 | 'etherScanLink': 'https://etherscan.io/token/0xc778417e063141139fce010982780140aa0cd5ab',
7 | 'address': '0xc778417e063141139fce010982780140aa0cd5ab'
8 | },
9 | {
10 | 'name': 'OmiseGO',
11 | 'symbol': 'OMG',
12 | 'approve': true,
13 | 'etherScanLink': 'https://etherscan.io/token/0x00df91984582e6e96288307e9c2f20b38c8fece9',
14 | 'address': '0x00df91984582e6e96288307e9c2f20b38c8fece9'
15 | },
16 | {
17 | 'name': 'Raiden',
18 | 'symbol': 'RDN',
19 | 'approve': true,
20 | 'etherScanLink': 'https://etherscan.io/token/0x3615757011112560521536258c1e7325ae3b48ae',
21 | 'address': '0x3615757011112560521536258c1e7325ae3b48ae'
22 | }
23 | ]
24 |
--------------------------------------------------------------------------------
/test/resources/add-token-pair/rinkeby/RDN_OMG.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // RDN
3 | tokenA: {
4 | symbol: 'RDN',
5 | address: '0x3615757011112560521536258c1e7325ae3b48ae',
6 | // Check ETH oracle (i.e 500 USD/ETH)
7 | // 10000$ = -/500 ETH = 20 ETH
8 | funding: 40000
9 | },
10 | // OMG
11 | tokenB: {
12 | symbol: 'OMG',
13 | address: '0x00df91984582e6e96288307e9c2f20b38c8fece9',
14 | funding: 0
15 | },
16 | // Price:
17 | // https://www.coingecko.com/en/price_charts/omisego/eth
18 | // https://www.coingecko.com/en/price_charts/raiden-network/eth
19 | //
20 | // The price should be in OMG/RDN (since its the RDN-OMG auction)
21 | // - ETH-RDN Price = 530 RDN/WETH
22 | // - ETH-OMG Price = 101 OMG/WETH
23 | // - RDN-OMG Price = 101/630 = 0,1603174603 OMG/RDN
24 | initialPrice: {
25 | numerator: 101,
26 | denominator: 630
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/test/test-tokens/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rinkeby-test-tokens",
3 | "version": "1.0.0",
4 | "description": "Just a small truffle project to deploy test tokens for testing in rinkeby.",
5 | "main": "index.js",
6 | "scripts": {
7 | "preversion": "npm run restore",
8 | "restore": "rm -rf build && npm run compile && npm run networks-reset",
9 | "networks-reset": "mkdir -p build/contracts && truffle networks --clean && npm run networks-inject",
10 | "networks-extract": "node src/extract_network_info.js",
11 | "networks-inject": "node src/inject_network_info.js",
12 | "compile": "truffle compile",
13 | "networks": "truffle networks",
14 | "migrate": "truffle migrate"
15 | },
16 | "license": "ISC",
17 | "dependencies": {
18 | "@gnosis.pm/util-contracts": "^2.0.0"
19 | },
20 | "devDependencies": {
21 | "truffle": "^5.0.5",
22 | "truffle-contract": "^3.0.6",
23 | "truffle-hdwallet-provider": "1.0.4"
24 | }
25 | }
--------------------------------------------------------------------------------
/contracts/DxDevDependencies.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | // NOTE:
4 | // This file porpouse is just to make sure truffle compiles all of depending
5 | // contracts when we are in development.
6 | //
7 | // For other environments, we just use the compiled contracts from the NPM
8 | // package
9 |
10 | // TODO: Use the same getter pattern also for dependencies
11 | import "@gnosis.pm/util-contracts/contracts/GnosisStandardToken.sol";
12 | import "@gnosis.pm/util-contracts/contracts/EtherToken.sol";
13 | import "@gnosis.pm/gno-token/contracts/TokenGNO.sol";
14 | import "@gnosis.pm/owl-token/contracts/TokenOWLProxy.sol";
15 | import "@gnosis.pm/owl-token/contracts/OWLAirdrop.sol";
16 |
17 | // DX contracts
18 | import "./Oracle/Medianizer.sol";
19 | import "./TokenFRT.sol";
20 | import "./TokenFRTProxy.sol";
21 | import "./DutchExchange.sol";
22 | import "./DutchExchangeHelper.sol";
23 | import "./DutchExchangeProxy.sol";
24 |
25 |
26 | contract DxDevDependencies {}
27 |
--------------------------------------------------------------------------------
/contracts/ForTestingOnly/BadToken.sol:
--------------------------------------------------------------------------------
1 | /// Implements ERC 20 Token standard: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
2 | pragma solidity ^0.5.2;
3 |
4 |
5 | /// @title Abstract token contract - Functions to be implemented by token contracts
6 | contract BadToken {
7 |
8 | /*
9 | * Events
10 | */
11 | event Transfer(address indexed from, address indexed to, uint value);
12 | event Approval(address indexed owner, address indexed spender, uint value);
13 |
14 | /*
15 | * Public functions
16 | */
17 | function transfer(address to, uint value) public;
18 | function transferFrom(address from, address to, uint value) public;
19 | function approve(address spender, uint value) public returns (bool);
20 | function balanceOf(address owner) public view returns (uint);
21 | function allowance(address owner, address spender) public view returns (uint);
22 | function totalSupply() public view returns (uint);
23 | }
24 |
--------------------------------------------------------------------------------
/src/migrations-truffle-4/2_migrate_dependencies.js:
--------------------------------------------------------------------------------
1 | const deployUtils = require('@gnosis.pm/util-contracts/src/migrations-truffle-5')
2 | const deployGno = require('@gnosis.pm/gno-token/src/migrations-truffle-5')
3 | const deployOwl = require('@gnosis.pm/owl-token/src/migrations-truffle-5')
4 |
5 | function migrate ({
6 | artifacts,
7 | deployer,
8 | network,
9 | accounts,
10 | initialTokenAmount,
11 | gnoLockPeriodInHours,
12 | web3
13 | }) {
14 | if (network === 'development') {
15 | const deployParams = {
16 | artifacts,
17 | deployer,
18 | network,
19 | accounts,
20 | initialTokenAmount,
21 | gnoLockPeriodInHours,
22 | web3
23 | }
24 | deployer
25 | .then(() => deployUtils(deployParams))
26 | .then(() => deployGno(deployParams))
27 | .then(() => deployOwl(deployParams))
28 | } else {
29 | console.log('Not in development, so nothing to do. Current network is %s', network)
30 | }
31 | }
32 |
33 | module.exports = migrate
34 |
--------------------------------------------------------------------------------
/.solcover.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | port: 8556,
3 | skipFiles: [
4 | 'Migrations.sol',
5 | 'Tokens/EtherToken.sol',
6 | 'Tokens/GnosisStandardToken.sol',
7 | 'ForTestingOnly'
8 | ],
9 | testrpcOptions: '--port 8556 --account=0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d,50000000000000000000000 --account=0x6cbed15c793ce57650b9877cf6fa156fbef513c4e6134f022a85b1ffdd59b2a1,50000000000000000000000 --account=0x6370fd033278c143179d81c5526140625662b8daa446c22ee2d73db3707e620c,50000000000000000000000 --account=0x646f1ce2fdad0e6deeeb5c7e8e5543bdde65e86029e2fd9fc169899c440a7913,50000000000000000000000 --account=0xadd53f9a7e588d003326d1cbf9e4a43c061aadd9bc938c843a79e7b4fd2ad743,50000000000000000000000 --account=0x395df67f0c2d2d9fe1ad08d1bc8b6627011959b79c53d7dd6a3536a33ab8a4fd,50000000000000000000000 --account=0xe485d098507f54e7733a205420dfddbe58db035fa577fc294ebd14db90767a52,50000000000000000000000',
10 | testCommand: 'truffle test test/*.spec.js -s',
11 | copyPackages: ['@gnosis.pm'],
12 | };
13 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | #.travis.yml
2 | sudo: required
3 | dist: trusty
4 | language: node_js
5 | node_js:
6 | - '10'
7 | cache: npm
8 | before_install:
9 | - rm -rf node_modules
10 | - npm install -g ganache-cli@6.4.3
11 | install:
12 | - npm install
13 | before_script:
14 | - ganache-cli --defaultBalanceEther 500000000 > /dev/null &
15 | - sleep 5
16 | #replace solidity-parser for coverage report
17 | - curl https://raw.githubusercontent.com/maxsam4/solidity-parser/solidity-0.5/build/parser.js --output $TRAVIS_BUILD_DIR/node_modules/solidity-parser-sc/build/parser.js
18 | #script:
19 | #- cd $TRAVIS_BUILD_DIR/travscripts
20 | #- "chmod +x ./BranchScript.sh && ./BranchScript.sh"
21 | jobs:
22 | include:
23 | - stage: script
24 | script:
25 | - cd $TRAVIS_BUILD_DIR/travscripts
26 | - "chmod +x ./BranchScript.sh && ./BranchScript.sh"
27 | - stage: script
28 | script:
29 | - cd $TRAVIS_BUILD_DIR/travscripts
30 | - "chmod +x ./AfterScript.sh && ./AfterScript.sh"
31 |
--------------------------------------------------------------------------------
/src/migrations-truffle-5/2_migrate_dependencies.js:
--------------------------------------------------------------------------------
1 | // TODO: Provide a index.js that migrate all in utils, GNO and OWL
2 | const deployUtils = require('@gnosis.pm/util-contracts/src/migrations-truffle-5')
3 | const deployGno = require('@gnosis.pm/gno-token/src/migrations-truffle-5')
4 | const deployOwl = require('@gnosis.pm/owl-token/src/migrations-truffle-5')
5 |
6 | async function migrate({
7 | artifacts,
8 | deployer,
9 | network,
10 | accounts,
11 | web3,
12 | initialTokenAmount,
13 | gnoLockPeriodInHours
14 | }) {
15 | if (network === 'development') {
16 | const deployParams = {
17 | artifacts,
18 | deployer,
19 | network,
20 | accounts,
21 | initialTokenAmount,
22 | gnoLockPeriodInHours,
23 | web3
24 | }
25 |
26 | await deployUtils(deployParams)
27 | await deployGno(deployParams)
28 | await deployOwl(deployParams)
29 | } else {
30 | console.log('Not in development, so nothing to do. Current network is %s', network)
31 | }
32 | }
33 |
34 | module.exports = migrate
35 |
--------------------------------------------------------------------------------
/test/resources/add-token-pair/kovan/RDN_OMG.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // RDN
3 | tokenA: {
4 | symbol: 'RDN',
5 | address: "0x3615757011112560521536258c1e7325ae3b48ae",
6 | // Check ETH oracle (i.e 730 USD/ETH)
7 | // 10$ = 10/730 ETH = 0.01369863014 ETH
8 | // Check price for WETH-RDN in the DX (i.e. 450 RDN/ETH)
9 | // i.e cli closing-price-official WETH-RDN 1
10 | // 0.0137 ETH = 0.0137 * 450 = 6.165 RDN
11 | funding: 6.165
12 | },
13 | // OMG
14 | tokenB: {
15 | symbol: 'OMG',
16 | address: "0x00df91984582e6e96288307e9c2f20b38c8fece9",
17 | funding: 0
18 | },
19 | // Price:
20 | // https://www.coingecko.com/en/price_charts/omisego/eth
21 | // https://www.coingecko.com/en/price_charts/raiden-network/eth
22 | //
23 | // The price should be in OMG/RDN (since its the RDN-OMG auction)
24 | // - ETH-RDN Price = 450 RDN/WETH
25 | // - ETH-OMG Price = 57 OMG/WETH
26 | // - RDN-OMG Price = 57/450 = 0,126666666 OMG/RDN
27 | initialPrice: {
28 | numerator: 57,
29 | denominator: 450
30 | }
31 | }
--------------------------------------------------------------------------------
/src/truffle/get-abi-encoded-params.js:
--------------------------------------------------------------------------------
1 | /* global artifacts */
2 | /* eslint no-undef: "error" */
3 |
4 | var abi = require('ethereumjs-abi')
5 |
6 | async function getAbiEncodedParams () {
7 | const DutchExchange = artifacts.require('DutchExchange')
8 | const TokenFRT = artifacts.require('TokenFRT')
9 |
10 | const dxMasterAddress = DutchExchange.address
11 | const frt = await TokenFRT.deployed()
12 | const owner = await frt.owner.call()
13 |
14 | const dxProxyParams = _getAbiEncodedParams([ 'address' ], [ dxMasterAddress ])
15 | const frtParams = _getAbiEncodedParams([ 'address' ], [ owner ])
16 |
17 | console.log('Abi encoded params')
18 | console.log('------------------')
19 | console.log('\tDutchExchangeProxy params: %s', dxProxyParams)
20 | console.log('\tTokenFRT params: %s', frtParams)
21 | }
22 |
23 | function _getAbiEncodedParams (parameterTypes, parameterValues) {
24 | var encoded = abi.rawEncode(parameterTypes, parameterValues)
25 |
26 | return encoded.toString('hex')
27 | }
28 |
29 | module.exports = callback => {
30 | getAbiEncodedParams()
31 | .then(callback)
32 | .catch(callback)
33 | }
34 |
--------------------------------------------------------------------------------
/src/migrations-truffle-5/4_deploy_FRT.js:
--------------------------------------------------------------------------------
1 | async function migrate ({
2 | artifacts,
3 | deployer,
4 | network,
5 | accounts
6 | }) {
7 | const account = accounts[0]
8 | const TokenFRT = artifacts.require('TokenFRT')
9 | const TokenFRTProxy = artifacts.require('TokenFRTProxy')
10 | const { Math } = _getDependencies(artifacts, network, deployer)
11 | await Math.deployed()
12 |
13 | console.log('Link math lib to TokenFrt')
14 | await deployer.link(Math, [TokenFRT, TokenFRTProxy])
15 |
16 | console.log('Deploying TokenFRT with owner: %s', account)
17 | await deployer.deploy(TokenFRT, account)
18 | await deployer.deploy(TokenFRTProxy, TokenFRT.address, account)
19 | }
20 |
21 | function _getDependencies (artifacts, network, deployer) {
22 | let Math
23 | if (network === 'development') {
24 | Math = artifacts.require('GnosisMath')
25 | } else {
26 | const contract = require('truffle-contract')
27 | Math = contract(require('@gnosis.pm/util-contracts/build/contracts/GnosisMath'))
28 | Math.setProvider(deployer.provider)
29 | }
30 |
31 | return {
32 | Math
33 | }
34 | }
35 |
36 | module.exports = migrate
37 |
--------------------------------------------------------------------------------
/scripts/extractTopTokensEtherscanWeb.js:
--------------------------------------------------------------------------------
1 | // http://etherscan.io/tokens
2 | function toArray (items) {
3 | return [].slice.call(items)
4 | }
5 |
6 | var rowsHtml = document.querySelectorAll('#ContentPlaceHolder1_divresult tr')
7 | var rows = toArray(rowsHtml).slice(1)
8 | var tokens = rows
9 | .map(row => row.querySelector(':nth-child(3) h5 a'))
10 | .map(link => {
11 | var nameAndSymbolRegex = /([\w\s]+) \((\w+)\)/gi
12 | var addressRegex = /https?:\/\/etherscan.io\/token\/0x(\w+)/gi
13 | let nameAndSymbolMatch = nameAndSymbolRegex.exec(link.innerText)
14 | let addressMatch = addressRegex.exec(link.href)
15 |
16 | let name, symbol, address
17 | if (nameAndSymbolMatch) {
18 | name = nameAndSymbolMatch[1]
19 | symbol = nameAndSymbolMatch[2]
20 | }
21 | if (addressMatch) {
22 | address = '0x' + addressMatch[1]
23 | }
24 |
25 | if (nameAndSymbolMatch) {
26 | return {
27 | name,
28 | symbol,
29 | address,
30 | approve: true,
31 | etherScanLink: link.href
32 | }
33 | }
34 | })
35 |
36 | console.log(tokens)
37 | console.log(JSON.stringify(tokens, null, 2))
38 |
--------------------------------------------------------------------------------
/contracts/ForTestingOnly/InternalTests.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "../DutchExchange.sol";
4 |
5 |
6 | contract InternalTests is DutchExchange {
7 | constructor(
8 | TokenFRT _FRT,
9 | TokenOWL _OWL,
10 | address _owner,
11 | address _ETH,
12 | PriceOracleInterface _ETHUSDOracle,
13 | uint _thresholdNewTokenPair,
14 | uint _thresholdNewAuction
15 | ) public {
16 | setupDutchExchange(
17 | _FRT,
18 | _OWL,
19 | _owner,
20 | _ETH,
21 | _ETHUSDOracle,
22 | _thresholdNewTokenPair,
23 | _thresholdNewAuction
24 | );
25 | }
26 |
27 | function settleFeePub(address primaryToken, address secondaryToken, uint auctionIndex, address user, uint amount)
28 | public
29 | returns (uint)
30 | {
31 | return super.settleFee(primaryToken, secondaryToken, auctionIndex, amount);
32 | }
33 |
34 | function getFeeRatioForJS(address user) public view returns (uint feeRatioNum, uint feeRatioDen) {
35 | (feeRatioNum, feeRatioDen) = super.getFeeRatio(user);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/migrations-truffle-4/4_deploy_FRT.js:
--------------------------------------------------------------------------------
1 | function migrate ({
2 | artifacts,
3 | deployer,
4 | network,
5 | accounts
6 | }) {
7 | const TokenFRT = artifacts.require('TokenFRT')
8 | const TokenFRTProxy = artifacts.require('TokenFRTProxy')
9 |
10 | const { Math } = _getDependencies(artifacts, network, deployer)
11 |
12 | return deployer
13 | .then(() => Math.deployed())
14 | .then(() => deployer.link(Math, [TokenFRT, TokenFRTProxy]))
15 | .then(() => deployer.deploy(TokenFRT))
16 | // proxiedAddr, ownerAddr
17 | .then(() => {
18 | console.log('Deploying TokenFRTProxy with ACCOUNT ==> ', accounts[0])
19 | return deployer.deploy(TokenFRTProxy, TokenFRT.address, accounts[0])
20 | })
21 | }
22 |
23 | function _getDependencies (artifacts, network, deployer) {
24 | let Math
25 | if (network === 'development') {
26 | Math = artifacts.require('GnosisMath')
27 | } else {
28 | const contract = require('truffle-contract')
29 | Math = contract(require('@gnosis.pm/util-contracts/build/contracts/GnosisMath'))
30 | Math.setProvider(deployer.provider)
31 | }
32 |
33 | return {
34 | Math
35 | }
36 | }
37 |
38 | module.exports = migrate
39 |
--------------------------------------------------------------------------------
/test/trufflescripts/get_account_deposits.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | const { getTokenDeposits } = require('./utils/contracts')(artifacts)
3 |
4 | const argv = require('minimist')(process.argv.slice(2), { string: 'a' })
5 |
6 | /**
7 | * truffle exec test/trufflescripts/get_account_deposits.js
8 | * get ETH and GNO deposits for seller and buyer accounts
9 | * @flags:
10 | * -a
and for the given account
11 | */
12 |
13 | module.exports = async () => {
14 | // web3 is available in the global context
15 | const [, seller, buyer] = web3.eth.accounts
16 |
17 | const getDepositsForAccounts = (...accounts) => Promise.all(accounts.map(acc => getTokenDeposits(acc)))
18 |
19 |
20 | const [sellerBal, buyerBal] = await getDepositsForAccounts(seller, buyer)
21 |
22 |
23 | console.log(`Seller:\t${sellerBal.ETH}\tETH,\t${sellerBal.GNO}\tGNO`)
24 | console.log(`Buyer:\t${buyerBal.ETH}\tETH,\t${buyerBal.GNO}\tGNO,`)
25 |
26 | if (argv.a) {
27 | const [{ ETH, GNO, FRT, OWL }] = await getDepositsForAccounts(argv.a)
28 |
29 | console.log(`\nAccount at ${argv.a} address`)
30 | console.log(`Deposit:\t${ETH}\tETH,\t${GNO}\tGNO,\t${FRT}\tFRT,\t${OWL}\tOWL`)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/migrations-truffle-5/EXAMPLE_migrate_all.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 |
4 | const deployUtils = require('@gnosis.pm/util-contracts/src/migrations-truffle-5')
5 | const deployGno = require('@gnosis.pm/gno-token/src/migrations-truffle-5')
6 | const deployOwl = require('@gnosis.pm/owl-token/src/migrations-truffle-5')
7 |
8 | const migrationsDx = require('@gnosis.pm/dx-contracts/src/migrations-truffle-5')
9 |
10 | module.exports = async (deployer, network, accounts) => {
11 | if (network === 'development') {
12 | const deployParams = {
13 | artifacts,
14 | deployer,
15 | network,
16 | accounts,
17 | web3,
18 | initialTokenAmount: process.env.GNO_TOKEN_AMOUNT,
19 | gnoLockPeriodInHours: process.env.GNO_LOCK_PERIOD_IN_HOURS,
20 | thresholdNewTokenPairUsd: process.env.GNO_LOCK_PERIOD_IN_HOURS,
21 | thresholdAuctionStartUsd: process.env.GNO_LOCK_PERIOD_IN_HOURS
22 | }
23 |
24 | await deployUtils(deployParams)
25 | await deployGno(deployParams)
26 | await deployOwl(deployParams)
27 | await migrationsDx(deployParams)
28 | } else {
29 | throw new Error('Migrations are just for development. Current network is %s', network)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/test/test-tokens/contracts/TestToken.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "@gnosis.pm/util-contracts/contracts/GnosisStandardToken.sol";
4 |
5 | contract TestToken is GnosisStandardToken {
6 | address public minter;
7 | string public symbol;
8 | string public name;
9 | uint8 public decimals;
10 |
11 | modifier onlyMinter() {
12 | require(msg.sender == minter);
13 | _;
14 | }
15 |
16 | constructor(string memory _symbol, string memory _name, uint8 _decimals, uint amount) public {
17 | minter = msg.sender;
18 | symbol = _symbol;
19 | name = _name;
20 | decimals = _decimals;
21 | balances[minter] = amount;
22 | totalTokens = amount;
23 |
24 | emit SetMinter(minter);
25 | emit Mint(minter, amount);
26 | }
27 |
28 | function mint(address _address, uint amount) public onlyMinter {
29 | balances[_address] += amount;
30 | totalTokens += amount;
31 | emit Mint(_address, amount);
32 | }
33 |
34 | function changeMinter(address _minter) public onlyMinter {
35 | minter = _minter;
36 | emit SetMinter(minter);
37 | }
38 |
39 | event Mint(address indexed token, uint amount);
40 |
41 | event SetMinter(address indexed minter);
42 | }
43 |
--------------------------------------------------------------------------------
/contracts/Oracle/PriceFeed.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 | /// price-feed.sol
3 |
4 | // Copyright (C) 2017 DappHub, LLC
5 |
6 | // Licensed under the Apache License, Version 2.0 (the "License").
7 | // You may not use this file except in compliance with the License.
8 |
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND (express or implied).
12 |
13 | import "../Oracle/DSThing.sol";
14 |
15 |
16 | contract PriceFeed is DSThing {
17 | uint128 val;
18 | uint32 public zzz;
19 |
20 | function peek() public view returns (bytes32, bool) {
21 | return (bytes32(uint256(val)), block.timestamp < zzz);
22 | }
23 |
24 | function read() public view returns (bytes32) {
25 | assert(block.timestamp < zzz);
26 | return bytes32(uint256(val));
27 | }
28 |
29 | function post(uint128 val_, uint32 zzz_, address med_) public payable note auth {
30 | val = val_;
31 | zzz = zzz_;
32 | (bool success, ) = med_.call(abi.encodeWithSignature("poke()"));
33 | require(success, "The poke must succeed");
34 | }
35 |
36 | function void() public payable note auth {
37 | zzz = 0;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/contracts/base/TokenWhitelist.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "./AuctioneerManaged.sol";
4 |
5 |
6 | contract TokenWhitelist is AuctioneerManaged {
7 | // Mapping that stores the tokens, which are approved
8 | // Only tokens approved by auctioneer generate frtToken tokens
9 | // addressToken => boolApproved
10 | mapping(address => bool) public approvedTokens;
11 |
12 | event Approval(address indexed token, bool approved);
13 |
14 | /// @dev for quick overview of approved Tokens
15 | /// @param addressesToCheck are the ERC-20 token addresses to be checked whether they are approved
16 | function getApprovedAddressesOfList(address[] calldata addressesToCheck) external view returns (bool[] memory) {
17 | uint length = addressesToCheck.length;
18 |
19 | bool[] memory isApproved = new bool[](length);
20 |
21 | for (uint i = 0; i < length; i++) {
22 | isApproved[i] = approvedTokens[addressesToCheck[i]];
23 | }
24 |
25 | return isApproved;
26 | }
27 |
28 | function updateApprovalOfToken(address[] memory token, bool approved) public onlyAuctioneer {
29 | for (uint i = 0; i < token.length; i++) {
30 | approvedTokens[token[i]] = approved;
31 | emit Approval(token[i], approved);
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/contracts/base/DxUpgrade.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "./DxMath.sol";
4 | import "./AuctioneerManaged.sol";
5 | import "@gnosis.pm/util-contracts/contracts/Proxy.sol";
6 |
7 |
8 | contract DxUpgrade is Proxied, AuctioneerManaged, DxMath {
9 | uint constant WAITING_PERIOD_CHANGE_MASTERCOPY = 30 days;
10 |
11 | address public newMasterCopy;
12 | // Time when new masterCopy is updatabale
13 | uint public masterCopyCountdown;
14 |
15 | event NewMasterCopyProposal(address newMasterCopy);
16 |
17 | function startMasterCopyCountdown(address _masterCopy) public onlyAuctioneer {
18 | require(_masterCopy != address(0), "The new master copy must be a valid address");
19 |
20 | // Update masterCopyCountdown
21 | newMasterCopy = _masterCopy;
22 | masterCopyCountdown = add(block.timestamp, WAITING_PERIOD_CHANGE_MASTERCOPY);
23 | emit NewMasterCopyProposal(_masterCopy);
24 | }
25 |
26 | function updateMasterCopy() public {
27 | require(newMasterCopy != address(0), "The new master copy must be a valid address");
28 | require(block.timestamp >= masterCopyCountdown, "The master contract cannot be updated in a waiting period");
29 |
30 | // Update masterCopy
31 | masterCopy = newMasterCopy;
32 | newMasterCopy = address(0);
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/migrations-truffle-4/EXAMPLE_migrate_all.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 |
4 | // Note: Use "migrations-truffle-5" for truffle 5
5 |
6 | const deployUtils = require('@gnosis.pm/util-contracts/src/migrations-truffle-4')
7 | const deployGno = require('@gnosis.pm/gno-token/src/migrations-truffle-4')
8 | const deployOwl = require('@gnosis.pm/owl-token/src/migrations-truffle-4')
9 | const migrationsDx = require('@gnosis.pm/dx-contracts/src/migrations-truffle-4')
10 |
11 | module.exports = (deployer, network, accounts) => {
12 | if (network === 'development') {
13 | const deployParams = {
14 | artifacts,
15 | deployer,
16 | network,
17 | accounts,
18 | web3,
19 | initialTokenAmount: process.env.GNO_TOKEN_AMOUNT,
20 | gnoLockPeriodInHours: process.env.GNO_LOCK_PERIOD_IN_HOURS,
21 | thresholdNewTokenPairUsd: process.env.GNO_LOCK_PERIOD_IN_HOURS,
22 | thresholdAuctionStartUsd: process.env.GNO_LOCK_PERIOD_IN_HOURS
23 | }
24 |
25 | deployer
26 | .then(() => deployUtils(deployParams))
27 | .then(() => deployGno(deployParams))
28 | .then(() => deployOwl(deployParams))
29 | .then(() => migrationsDx(deployParams))
30 | } else {
31 | throw new Error('Migrations are just for development. Current network is %s', network)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/contracts/base/SafeTransfer.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.0;
2 |
3 | import "@gnosis.pm/util-contracts/contracts/Token.sol";
4 |
5 | interface BadToken {
6 | function transfer(address to, uint value) external;
7 | function transferFrom(address from, address to, uint value) external;
8 | }
9 |
10 |
11 | contract SafeTransfer {
12 | function safeTransfer(address token, address to, uint value, bool from) internal returns (bool result) {
13 | if (from) {
14 | BadToken(token).transferFrom(msg.sender, address(this), value);
15 | } else {
16 | BadToken(token).transfer(to, value);
17 | }
18 |
19 | // solium-disable-next-line security/no-inline-assembly
20 | assembly {
21 | switch returndatasize
22 | case 0 {
23 | // This is our BadToken
24 | result := not(0) // result is true
25 | }
26 | case 32 {
27 | // This is our GoodToken
28 | returndatacopy(0, 0, 32)
29 | result := mload(0) // result == returndata of external call
30 | }
31 | default {
32 | // This is not an ERC20 token
33 | result := 0
34 | }
35 | }
36 | return result;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/contracts/Oracle/DSAuth.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 |
4 | contract DSAuthority {
5 | function canCall(address src, address dst, bytes4 sig) public view returns (bool);
6 | }
7 |
8 |
9 | contract DSAuthEvents {
10 | event LogSetAuthority(address indexed authority);
11 | event LogSetOwner(address indexed owner);
12 | }
13 |
14 |
15 | contract DSAuth is DSAuthEvents {
16 | DSAuthority public authority;
17 | address public owner;
18 |
19 | constructor() public {
20 | owner = msg.sender;
21 | emit LogSetOwner(msg.sender);
22 | }
23 |
24 | function setOwner(address owner_) public auth {
25 | owner = owner_;
26 | emit LogSetOwner(owner);
27 | }
28 |
29 | function setAuthority(DSAuthority authority_) public auth {
30 | authority = authority_;
31 | emit LogSetAuthority(address(authority));
32 | }
33 |
34 | modifier auth {
35 | require(isAuthorized(msg.sender, msg.sig), "It must be an authorized call");
36 | _;
37 | }
38 |
39 | function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
40 | if (src == address(this)) {
41 | return true;
42 | } else if (src == owner) {
43 | return true;
44 | } else if (authority == DSAuthority(0)) {
45 | return false;
46 | } else {
47 | return authority.canCall(src, address(this), sig);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/test/trufflescripts/get_account_balances.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | const { getTokenBalances } = require('./utils/contracts')(artifacts)
3 |
4 | const argv = require('minimist')(process.argv.slice(2), { string: 'a' })
5 |
6 | /**
7 | * truffle exec test/trufflescripts/get_account_balances.js
8 | * get ETH and GNO balances for seller and buyer accounts
9 | * @flags:
10 | * -a and for the given account
11 | */
12 |
13 | module.exports = async () => {
14 | // web3 is available in the global context
15 | const [master, seller, buyer] = web3.eth.accounts
16 |
17 | const getBalancesForAccounts = (...accounts) => Promise.all(accounts.map(acc => getTokenBalances(acc)))
18 |
19 |
20 | const [masterBal, sellerBal, buyerBal] = await getBalancesForAccounts(master, seller, buyer)
21 |
22 |
23 | console.log(`Seller:\t${sellerBal.ETH}\tETH,\t${sellerBal.GNO}\tGNO,\t${sellerBal.FRT}\tFRT,\t${sellerBal.OWL}\tOWL`)
24 | console.log(`Buyer:\t${buyerBal.ETH}\tETH,\t${buyerBal.GNO}\tGNO,\t${buyerBal.FRT}\tFRT,\t${buyerBal.OWL}\tOWL`)
25 | console.log('________________________________________')
26 | console.log(`Master:\t${masterBal.ETH}\tETH,\t${masterBal.GNO}\tGNO,\t${masterBal.FRT}\tFRT,\t${masterBal.OWL}\tOWL`)
27 |
28 | if (argv.a) {
29 | const [{ ETH, GNO, FRT, OWL }] = await getBalancesForAccounts(argv.a)
30 |
31 | console.log(`\nAccount at ${argv.a} address`)
32 | console.log(`Balance:\t${ETH}\tETH,\t${GNO}\tGNO,\t${FRT}\tFRT,\t${OWL}\tOWL`)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/test/trufflescripts/revert.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | const { revertSnapshot } = require('./utils')(web3)
3 |
4 | const argv = require('minimist')(process.argv.slice(2), { string: 'a' })
5 |
6 | /**
7 | * truffle exec test/trufflescripts/claim_funds.js
8 | * to claim funds for the current auction for both seller and buyer,
9 | * from auction's sellerBalances and buyerBalances respectively
10 | * @flags:
11 | * --seller sellerBalance for seller only
12 | * --buyer buyerBalance for buyer only
13 | * -a seller|buyer| for the given address
14 | * -i for auction with given index
15 | * --last for last auction
16 | */
17 |
18 | module.exports = async () => {
19 | const snapshotID = argv.b || '0x01'
20 |
21 | const timeout = new Promise((resolve, reject) => setTimeout(() => reject(new Error('TIMED-OUT')), 1500))
22 | const race = Promise.race([timeout, revertSnapshot(snapshotID)])
23 | try {
24 | await race
25 | console.warn(`
26 | CAUTION: Reverting does NOT roll back time to snapshot time. You've been warned...
27 | `)
28 | console.log(`
29 | REVERTED TO SNAPSHOT-ID: # ${snapshotID}
30 | BLOCKNUMBER: ${web3.eth.blockNumber}
31 | `)
32 | } catch (e) {
33 | console.log(e)
34 |
35 | // Due to lock in rpc, kill w/Node
36 | process.on('exit', () => {
37 | console.log('KILLING SCRIPT')
38 | })
39 | process.exit()
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/contracts/base/EthOracle.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "../Oracle/PriceOracleInterface.sol";
4 | import "./AuctioneerManaged.sol";
5 | import "./DxMath.sol";
6 |
7 |
8 | contract EthOracle is AuctioneerManaged, DxMath {
9 | uint constant WAITING_PERIOD_CHANGE_ORACLE = 30 days;
10 |
11 | // Price Oracle interface
12 | PriceOracleInterface public ethUSDOracle;
13 | // Price Oracle interface proposals during update process
14 | PriceOracleInterface public newProposalEthUSDOracle;
15 |
16 | uint public oracleInterfaceCountdown;
17 |
18 | event NewOracleProposal(PriceOracleInterface priceOracleInterface);
19 |
20 | function initiateEthUsdOracleUpdate(PriceOracleInterface _ethUSDOracle) public onlyAuctioneer {
21 | require(address(_ethUSDOracle) != address(0), "The oracle address must be valid");
22 | newProposalEthUSDOracle = _ethUSDOracle;
23 | oracleInterfaceCountdown = add(block.timestamp, WAITING_PERIOD_CHANGE_ORACLE);
24 | emit NewOracleProposal(_ethUSDOracle);
25 | }
26 |
27 | function updateEthUSDOracle() public {
28 | require(address(newProposalEthUSDOracle) != address(0), "The new proposal must be a valid addres");
29 | require(
30 | oracleInterfaceCountdown < block.timestamp,
31 | "It's not possible to update the oracle during the waiting period"
32 | );
33 | ethUSDOracle = newProposalEthUSDOracle;
34 | newProposalEthUSDOracle = PriceOracleInterface(0);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/test/trufflescripts/deposit.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | const { getTokenDeposits, depositToDX } = require('./utils/contracts')(artifacts)
3 |
4 | const argv = require('minimist')(process.argv.slice(2), { string: 'a' })
5 |
6 | /**
7 | * truffle exec test/trufflescripts/deposit.js
8 | * to deposit funds to DutchExchange contracts
9 | * @flags:
10 | * --seller as the seller
11 | * --buyer as the buyer
12 | * -a as the given address
13 | * --eth ETH tokens
14 | * --gno GNO tokens
15 | */
16 |
17 | module.exports = async () => {
18 | if (!(argv.eth || argv.gno) || !(argv.seller || argv.buyer || argv.a)) {
19 | console.warn('No tokens or accounts specified')
20 | return
21 | }
22 |
23 | let account, accountName
24 | if (argv.a) account = accountName = argv.a
25 | else if (argv.seller) {
26 | [, account] = web3.eth.accounts
27 | accountName = 'Seller'
28 | } else {
29 | [, , account] = web3.eth.accounts
30 | accountName = 'Buyer'
31 | }
32 |
33 | console.log(`${accountName}`)
34 |
35 | let { ETH, GNO } = await getTokenDeposits(account)
36 | console.log(`Deposit was:\t${ETH}\tETH,\t${GNO}\tGNO`)
37 |
38 | const tokensToDeposit = { ETH: argv.eth, GNO: argv.gno, FRT: argv.frt, OWL: argv.owl }
39 |
40 | await depositToDX(account, tokensToDeposit);
41 |
42 | ({ ETH, GNO } = await getTokenDeposits(account))
43 | console.log(`Deposit is:\t${ETH}\tETH,\t${GNO}\tGNO`)
44 | }
45 |
--------------------------------------------------------------------------------
/test/trufflescripts/withdraw.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | const { getTokenDeposits, withrawFromDX } = require('./utils/contracts')(artifacts)
3 |
4 | const argv = require('minimist')(process.argv.slice(2), { string: 'a' })
5 |
6 | /**
7 | * truffle exec test/trufflescripts/withdraw.js
8 | * to withdraw funds from DutchExchange contract
9 | * @flags:
10 | * --seller as the seller
11 | * --buyer as the buyer
12 | * -a as the given address
13 | * --eth ETH tokens
14 | * --gno GNO tokens
15 | */
16 |
17 | module.exports = async () => {
18 | if (!(argv.eth || argv.gno) || !(argv.seller || argv.buyer || argv.a)) {
19 | console.warn('No tokens or accounts specified')
20 | return
21 | }
22 |
23 | let account, accountName
24 | if (argv.a) account = accountName = argv.a
25 | else if (argv.seller) {
26 | [, account] = web3.eth.accounts
27 | accountName = 'Seller'
28 | } else {
29 | [, , account] = web3.eth.accounts
30 | accountName = 'Buyer'
31 | }
32 |
33 | console.log(`${accountName}`)
34 |
35 | let { ETH, GNO } = await getTokenDeposits(account)
36 | console.log(`Deposit was:\t${ETH}\tETH,\t${GNO}\tGNO`)
37 |
38 | const tokensToWithdraw = { ETH: argv.eth, GNO: argv.gno, TUL: argv.tul, OWL: argv.owl }
39 |
40 | await withrawFromDX(account, tokensToWithdraw);
41 |
42 | ({ ETH, GNO } = await getTokenDeposits(account))
43 | console.log(`Deposit is:\t${ETH}\tETH,\t${GNO}\tGNO`)
44 | }
45 |
--------------------------------------------------------------------------------
/test/trufflescripts/utils/index.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 |
3 | module.exports = (web3) => {
4 | const getTime = (blockNumber = 'latest') => web3.eth.getBlock(blockNumber).timestamp
5 |
6 | const mineCurrentBlock = () => web3.currentProvider.send({
7 | jsonrpc: '2.0',
8 | method: 'evm_mine',
9 | params: [],
10 | id: 0,
11 | })
12 |
13 | const increaseTimeBy = (seconds, dontMine) => {
14 | if (seconds < 0) {
15 | throw new Error('Can\'t decrease time in testrpc')
16 | }
17 |
18 | if (seconds === 0) return
19 |
20 | web3.currentProvider.send({
21 | jsonrpc: '2.0',
22 | method: 'evm_increaseTime',
23 | params: [seconds],
24 | id: 0,
25 | })
26 |
27 | if (!dontMine) {
28 | mineCurrentBlock()
29 | }
30 | }
31 |
32 | const setTime = (seconds, dontMine) => {
33 | const increaseBy = seconds - getTime()
34 |
35 | increaseTimeBy(increaseBy, dontMine)
36 | }
37 |
38 | const makeSnapshot = () => web3.currentProvider.send({ jsonrpc: '2.0', method: 'evm_snapshot' }).result
39 |
40 | const revertSnapshot = snapshotID => new Promise((resolve, reject) => {
41 | web3.currentProvider.sendAsync({ jsonrpc: '2.0', method: 'evm_revert', params: [snapshotID] }, (err) => {
42 | if (!err) {
43 | console.log('Revert Success')
44 | resolve(snapshotID)
45 | } else {
46 | reject(err)
47 | }
48 | })
49 | })
50 |
51 | return {
52 | getTime,
53 | increaseTimeBy,
54 | setTime,
55 | makeSnapshot,
56 | revertSnapshot,
57 | mineCurrentBlock,
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/test/trufflescripts/give_tokens.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | const { getTokenBalances, giveTokens } = require('./utils/contracts')(artifacts)
3 |
4 | const argv = require('minimist')(process.argv.slice(2), { string: 'a' })
5 |
6 | /**
7 | * truffle exec test/trufflescripts/give_tokens.js
8 | * give tokens from master
9 | * @flags:
10 | * --seller to seller
11 | * --buyer to buyer
12 | * -a to the given address
13 | * --eth ETH tokens
14 | * --gno GNO tokens
15 | * --frt FRT tokens
16 | * --owl OWL tokens
17 | */
18 |
19 | module.exports = async () => {
20 | if (!(argv.eth > 0 || argv.gno > 0 || argv.frt > 0 || argv.owl > 0) || !(argv.seller || argv.buyer || argv.a)) {
21 | console.warn('No tokens or accounts specified')
22 | return
23 | }
24 |
25 | // web3 is available in the global context
26 | const [master, seller, buyer] = web3.eth.accounts
27 | const account = argv.seller ? seller : argv.buyer ? buyer : argv.a
28 | const accountName = argv.seller ? 'Seller' : argv.buyer ? 'Buyer' : `Acc ${argv.a}`
29 |
30 | console.log(`${accountName}`)
31 |
32 | let { ETH, GNO, FRT, OWL } = await getTokenBalances(account)
33 | console.log(`Balance was:\t${ETH}\tETH,\t${GNO}\tGNO,\t${FRT}\tFRT,\t${OWL}\tOWL`)
34 |
35 | const tokensToGive = { ETH: argv.eth, GNO: argv.gno, FRT: argv.frt, OWL: argv.owl }
36 |
37 | giveTokens(account, tokensToGive, master);
38 |
39 | ({ ETH, GNO, FRT, OWL } = await getTokenBalances(account))
40 | console.log(`Balance is:\t${ETH}\tETH,\t${GNO}\tGNO,\t${FRT}\tFRT,\t${OWL}\tOWL`)
41 | }
42 |
--------------------------------------------------------------------------------
/test/trufflescripts/topup_accounts.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | const { getTokenBalances, giveTokens } = require('./utils/contracts')(artifacts)
3 |
4 | const initBalances = {
5 | seller: { ETH: 1000, GNO: 100, FRT: 0, OWL: 100 },
6 | buyer: { ETH: 100, GNO: 1000, FRT: 0, OWL: 100 },
7 | }
8 |
9 | /**
10 | * truffle exec test/trufflescripts/topup_accounts.js
11 | * deposits ETH tokens in accounts names
12 | * and transfers other tokens from master account
13 | * so that seller and buyer balances are no less than initBalances fro respective tokens
14 | */
15 |
16 | module.exports = async () => {
17 | // web3 is available in the global context
18 | const [master, seller, buyer] = web3.eth.accounts
19 |
20 | let sellerBal = await getTokenBalances(seller)
21 | let buyerBal = await getTokenBalances(buyer)
22 |
23 | const topupIfNeeded = (acc, currentBal, neededBal) => {
24 | const diffBal = Object.keys(neededBal).reduce((accum, key) => {
25 | const left = neededBal[key] - (currentBal[key] || 0)
26 | if (left > 0) accum[key] = left
27 |
28 | return accum
29 | }, {})
30 |
31 | return giveTokens(acc, diffBal, master)
32 | }
33 |
34 | await topupIfNeeded(seller, sellerBal, initBalances.seller)
35 | await topupIfNeeded(buyer, buyerBal, initBalances.buyer)
36 |
37 | sellerBal = await getTokenBalances(seller)
38 | buyerBal = await getTokenBalances(buyer)
39 |
40 | console.log(`Seller:\t${sellerBal.ETH}\tETH,\t${sellerBal.GNO}\tGNO,\t${sellerBal.FRT}\tFRT,\t${sellerBal.OWL}\tOWL`)
41 | console.log(`Buyer:\t${buyerBal.ETH}\tETH,\t${buyerBal.GNO}\tGNO,\t${buyerBal.FRT}\tFRT,\t${buyerBal.OWL}\tOWL`)
42 | }
43 |
--------------------------------------------------------------------------------
/truffle.js:
--------------------------------------------------------------------------------
1 | const truffleConfig = require('@gnosis.pm/util-contracts/src/util/truffleConfig')
2 |
3 | const DEFAULT_GAS_PRICE_GWEI = 5
4 | const DEFAULT_GAS_LIMIT = 6721975
5 | const DEFAULT_MNEMONIC = 'candy maple cake sugar pudding cream honey rich smooth crumble sweet treat'
6 |
7 | // Load env vars
8 | require('dotenv').config()
9 |
10 | // Get the mnemonic
11 | const privateKey = process.env.PK
12 | let mnemonic = process.env.MNEMONIC
13 | if (!privateKey && !mnemonic) {
14 | mnemonic = DEFAULT_MNEMONIC
15 | }
16 |
17 | // Solc
18 | const compatibilityTruffle4 = false
19 | let solcUseDocker, solcVersion
20 | if (!compatibilityTruffle4) {
21 | // Use truffle 5
22 | solcUseDocker = process.env.SOLC_USE_DOCKER === 'true' || false
23 | solcVersion = '0.5.2'
24 | }
25 |
26 | // Gas price
27 | const gasPriceGWei = process.env.GAS_PRICE_GWEI || DEFAULT_GAS_PRICE_GWEI
28 |
29 | // Gas limit
30 | const gas = process.env.GAS_LIMIT || DEFAULT_GAS_LIMIT
31 |
32 | // Allow to add an aditional network (useful for docker-compose setups)
33 | // i.e. NETWORK='{ "name": "docker", "networkId": "99999", "url": "http://rpc:8545", "gas": "6700000", "gasPrice": "25000000000" }'
34 | let aditionalNetwork = process.env.NETWORK ? JSON.parse(process.env.NETWORK) : null
35 |
36 | module.exports = {
37 | ...truffleConfig({
38 | mnemonic,
39 | privateKey,
40 | urlRinkeby: 'https://rinkeby.infura.io/v3/9408f47dedf04716a03ef994182cf150',
41 | urlKovan: 'https://kovan.infura.io/v3/9408f47dedf04716a03ef994182cf150',
42 | urlMainnet: 'https://mainnet.infura.io/v3/9408f47dedf04716a03ef994182cf150',
43 | gasPriceGWei,
44 | gas,
45 | aditionalNetwork,
46 | optimizedEnabled: true,
47 | solcUseDocker,
48 | solcVersion,
49 | compatibilityTruffle4
50 | }),
51 | // https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options
52 | mocha: {
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/contracts/base/DxMath.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 |
4 | contract DxMath {
5 | // > Math fns
6 | function min(uint a, uint b) public pure returns (uint) {
7 | if (a < b) {
8 | return a;
9 | } else {
10 | return b;
11 | }
12 | }
13 |
14 | function atleastZero(int a) public pure returns (uint) {
15 | if (a < 0) {
16 | return 0;
17 | } else {
18 | return uint(a);
19 | }
20 | }
21 |
22 | /// @dev Returns whether an add operation causes an overflow
23 | /// @param a First addend
24 | /// @param b Second addend
25 | /// @return Did no overflow occur?
26 | function safeToAdd(uint a, uint b) public pure returns (bool) {
27 | return a + b >= a;
28 | }
29 |
30 | /// @dev Returns whether a subtraction operation causes an underflow
31 | /// @param a Minuend
32 | /// @param b Subtrahend
33 | /// @return Did no underflow occur?
34 | function safeToSub(uint a, uint b) public pure returns (bool) {
35 | return a >= b;
36 | }
37 |
38 | /// @dev Returns whether a multiply operation causes an overflow
39 | /// @param a First factor
40 | /// @param b Second factor
41 | /// @return Did no overflow occur?
42 | function safeToMul(uint a, uint b) public pure returns (bool) {
43 | return b == 0 || a * b / b == a;
44 | }
45 |
46 | /// @dev Returns sum if no overflow occurred
47 | /// @param a First addend
48 | /// @param b Second addend
49 | /// @return Sum
50 | function add(uint a, uint b) public pure returns (uint) {
51 | require(safeToAdd(a, b));
52 | return a + b;
53 | }
54 |
55 | /// @dev Returns difference if no overflow occurred
56 | /// @param a Minuend
57 | /// @param b Subtrahend
58 | /// @return Difference
59 | function sub(uint a, uint b) public pure returns (uint) {
60 | require(safeToSub(a, b));
61 | return a - b;
62 | }
63 |
64 | /// @dev Returns product if no overflow occurred
65 | /// @param a First factor
66 | /// @param b Second factor
67 | /// @return Product
68 | function mul(uint a, uint b) public pure returns (uint) {
69 | require(safeToMul(a, b));
70 | return a * b;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/contracts/Oracle/PriceOracleInterface.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | /*
4 | This contract is the interface between the MakerDAO priceFeed and our DX platform.
5 | */
6 |
7 | import "../Oracle/PriceFeed.sol";
8 | import "../Oracle/Medianizer.sol";
9 |
10 |
11 | contract PriceOracleInterface {
12 | address public priceFeedSource;
13 | address public owner;
14 | bool public emergencyMode;
15 |
16 | // Modifiers
17 | modifier onlyOwner() {
18 | require(msg.sender == owner, "Only the owner can do the operation");
19 | _;
20 | }
21 |
22 | /// @dev constructor of the contract
23 | /// @param _priceFeedSource address of price Feed Source -> should be maker feeds Medianizer contract
24 | constructor(address _owner, address _priceFeedSource) public {
25 | owner = _owner;
26 | priceFeedSource = _priceFeedSource;
27 | }
28 |
29 | /// @dev gives the owner the possibility to put the Interface into an emergencyMode, which will
30 | /// output always a price of 600 USD. This gives everyone time to set up a new pricefeed.
31 | function raiseEmergency(bool _emergencyMode) public onlyOwner {
32 | emergencyMode = _emergencyMode;
33 | }
34 |
35 | /// @dev updates the priceFeedSource
36 | /// @param _owner address of owner
37 | function updateCurator(address _owner) public onlyOwner {
38 | owner = _owner;
39 | }
40 |
41 | /// @dev returns the USDETH price
42 | function getUsdEthPricePeek() public view returns (bytes32 price, bool valid) {
43 | return Medianizer(priceFeedSource).peek();
44 | }
45 |
46 | /// @dev returns the USDETH price, ie gets the USD price from Maker feed with 18 digits, but last 18 digits are cut off
47 | function getUSDETHPrice() public view returns (uint256) {
48 | // if the contract is in the emergencyMode, because there is an issue with the oracle, we will simply return a price of 600 USD
49 | if (emergencyMode) {
50 | return 600;
51 | }
52 | (bytes32 price, ) = Medianizer(priceFeedSource).peek();
53 |
54 | // ensuring that there is no underflow or overflow possible,
55 | // even if the price is compromised
56 | uint priceUint = uint256(price)/(1 ether);
57 | if (priceUint == 0) {
58 | return 1;
59 | }
60 | if (priceUint > 1000000) {
61 | return 1000000;
62 | }
63 | return priceUint;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/migrations-truffle-4/3_deploy_price_feed.js:
--------------------------------------------------------------------------------
1 | const DEFAULT_ETH_USD_PRICE = process.env.ETH_USD_PRICE || 1100 // 500 USD/ETH
2 | const DEFAULT_FEED_EXPIRE_PERIOD_DAYS = process.env.FEED_EXPIRE_PERIOD_DAYS || 365 // 1 year
3 |
4 | function migrate ({
5 | artifacts,
6 | deployer,
7 | network,
8 | accounts,
9 | web3,
10 | ethUsdPrice = DEFAULT_ETH_USD_PRICE,
11 | feedExpirePeriodDays = DEFAULT_FEED_EXPIRE_PERIOD_DAYS
12 | }) {
13 | const Medianizer = artifacts.require('Medianizer')
14 | const PriceOracleInterface = artifacts.require('PriceOracleInterface')
15 | const PriceFeed = artifacts.require('PriceFeed')
16 |
17 | const medianizerAddress = getMedianizerAddress(Medianizer)
18 | const account = accounts[0]
19 | if (!medianizerAddress) {
20 | console.log(`Deploying Maker Dao feed contracts, because they weren't published in network "${network}" yet`)
21 | // Deployment of PriceFeedInfrastructure
22 | return deployer
23 | .deploy(PriceFeed)
24 | .then(() => deployer.deploy(Medianizer))
25 | .then(() => deployer.deploy(PriceOracleInterface, account, Medianizer.address))
26 | .then(() => Medianizer.deployed())
27 | .then(medianizer => medianizer.set(PriceFeed.address, { from: account }))
28 | .then(() => Promise.all([
29 | PriceFeed.deployed(),
30 | getTime(web3)
31 | ]))
32 | .then(([priceFeed, now]) => priceFeed.post(
33 | ethUsdPrice * 1e18,
34 | now + feedExpirePeriodDays * 24 * 60 * 60,
35 | Medianizer.address, {
36 | from: account
37 | })
38 | )
39 | } else {
40 | console.log(`No need to deploy the Medianizer. Using ${medianizerAddress} as the Medianizer address`)
41 | console.log('Deploying PriceOracleInterface with owner: %s', account)
42 | return deployer
43 | .deploy(PriceOracleInterface, account, Medianizer.address)
44 | }
45 | }
46 |
47 | function getMedianizerAddress (Medianizer) {
48 | try {
49 | return Medianizer.address
50 | } catch (error) {
51 | // Medianizer.address throw an error if there's no config address
52 | // As a result, only development should be deploying this contracts
53 | return null
54 | }
55 | }
56 |
57 | function getTime (web3) {
58 | return new Promise((resolve, reject) => {
59 | web3.eth.getBlock('latest', (err, block) => {
60 | if (err) {
61 | return reject(err)
62 | } else {
63 | resolve(block.timestamp)
64 | }
65 | })
66 | })
67 | }
68 |
69 | module.exports = migrate
70 |
--------------------------------------------------------------------------------
/test/dutchExchange-depositWithdrawBadToken.js:
--------------------------------------------------------------------------------
1 | /* global contract, assert, artifacts */
2 | /* eslint no-undef: "error" */
3 |
4 | const {
5 | BN_ZERO,
6 | log: utilsLog,
7 | gasLogger
8 | } = require('./utils')
9 |
10 | const { getContracts } = require('./testFunctions')
11 |
12 | const BadGNO = artifacts.require('BadGNO')
13 |
14 | // Test VARS
15 | let dx, badGNO
16 | let contracts
17 |
18 | const separateLogs = () => utilsLog('\n ----------------------------------')
19 | const log = (...args) => utilsLog('\t', ...args)
20 |
21 | contract('DutchExchange - depoist/withdraw BadToken', accounts => {
22 | const [master, seller1] = accounts
23 |
24 | const startBal = {
25 | startingETH: 90.0.toWei(),
26 | startingGNO: 90.0.toWei(),
27 | ethUSDPrice: 1008.0.toWei(),
28 | sellingAmount: 50.0.toWei()
29 | }
30 |
31 | beforeEach(separateLogs)
32 | afterEach(gasLogger)
33 |
34 | before(async () => {
35 | // get contracts
36 | contracts = await getContracts({ resetCache: true });
37 | // destructure contracts into upper state
38 | ({
39 | DutchExchange: dx
40 | } = contracts)
41 |
42 | badGNO = await BadGNO.new(10000.0.toWei(), { from: master })
43 | await Promise.all([
44 | badGNO.transfer(seller1, startBal.startingGNO, { from: master }),
45 | badGNO.approve(dx.address, startBal.startingGNO, { from: seller1 })
46 | ])
47 | })
48 |
49 | it('deposits bad ERC20 tokens', async () => {
50 | log('Depositing Bad GNO')
51 | const tx = await dx.deposit(badGNO.address, startBal.startingGNO, { from: seller1 })
52 | log('tx: ', JSON.stringify(tx.logs, null, 2))
53 | log('Succeeded Depositing Bad GNO')
54 | log('startBal.startingGNO: ', startBal.startingGNO)
55 |
56 | const deposited = await dx.balances(badGNO.address, seller1)
57 | log('deposited: ', deposited.toString())
58 |
59 | assert(deposited.eq(startBal.startingGNO), 'deposited amount was exactly equal startingGNO')
60 | })
61 |
62 | it('withdraws bad ERC20 tokens', async () => {
63 | log('Withdrawing Bad GNO')
64 | const tx = await dx.withdraw(badGNO.address, startBal.startingGNO, { from: seller1 })
65 | log('tx: ', JSON.stringify(tx.logs, null, 2))
66 | log('Succeeded Withdrawing Bad GNO')
67 | log('startBal.startingGNO: ', startBal.startingGNO)
68 |
69 | const deposited = await dx.balances(badGNO.address, seller1)
70 | log('deposited: ', deposited.toString())
71 |
72 | assert(deposited.eq(BN_ZERO), 'deposited amount is exactly 0 after startingGNO was withdrawn')
73 | })
74 | })
75 |
--------------------------------------------------------------------------------
/test/dutchExchange-DepositAndSell.spec.js:
--------------------------------------------------------------------------------
1 | /* global contract, assert */
2 | /* eslint no-undef: "error" */
3 |
4 | const {
5 | BN,
6 | timestamp,
7 | gasLogger
8 | } = require('./utils')
9 |
10 | const {
11 | getContracts,
12 | getAuctionIndex
13 | } = require('./testFunctions')
14 |
15 | // Test VARS
16 | let eth
17 | let gno
18 | let dx
19 |
20 | let contracts
21 |
22 | contract('DutchExchange deposit and sell tests', accounts => {
23 | const testingAccs = accounts.slice(1, 5)
24 |
25 | const ETHBalance = 50.0.toWei()
26 | const initialToken1Funding = 10.0.toWei()
27 |
28 | afterEach(gasLogger)
29 |
30 | before(async () => {
31 | // get contracts
32 | contracts = await getContracts({ resetCache: true });
33 | // destructure contracts into upper state
34 | ({
35 | DutchExchange: dx,
36 | EtherToken: eth,
37 | TokenGNO: gno
38 | } = contracts)
39 |
40 | await Promise.all(testingAccs.map(acc => Promise.all([
41 | eth.deposit({ from: acc, value: ETHBalance }),
42 | eth.approve(dx.address, ETHBalance, { from: acc })
43 | ])))
44 |
45 | await Promise.all(testingAccs.map(acc => dx.deposit(eth.address, ETHBalance.div(new BN('2')), { from: acc })))
46 | })
47 |
48 | it('Adds Token Pair', () => dx.addTokenPair(eth.address, gno.address, initialToken1Funding, 0, 2, 1, { from: accounts[1] }))
49 |
50 | it('DX Auction idx = 1 + Auction Start Time is > timestamp NOW [auction not started]', async () => {
51 | const [auctionIndex, auctionStart] = await Promise.all([
52 | getAuctionIndex(),
53 | dx.getAuctionStart.call(eth.address, gno.address)
54 | ])
55 | assert.equal(auctionIndex, 1, 'Auction index should be moved to 1')
56 | assert.isAbove(auctionStart.toNumber(), await timestamp(), 'auction time should be above now')
57 | })
58 |
59 | it('DX balances cannot be more than amt deposited initially', () => Promise.all(testingAccs.map(async acc => {
60 | assert(await dx.balances.call(eth.address, acc) <= ETHBalance.div(new BN('2')), 'Balances cannot be more than ETHBalance / 2')
61 | })))
62 |
63 | it('DX Sell Vol = 0 - nothing posted in sell order', async () => {
64 | assert.equal((await dx.sellVolumesCurrent.call(eth.address, gno.address)).toString(), (initialToken1Funding * 0.995).toString(), 'SellVolumesCurrent = 0')
65 | })
66 |
67 | it('Deposits some ETH into DX and Posts Sell Order at same time', () => Promise.all(testingAccs.map(async acc => {
68 | await dx.depositAndSell(eth.address, gno.address, 4.0.toWei(), { from: acc })
69 | const fee = 0.995
70 |
71 | assert.equal((await dx.sellVolumesCurrent.call(eth.address, gno.address)).toString(), (((4.0.toWei() * testingAccs.length) * fee) + (initialToken1Funding * 0.995)).toString(), 'SellVolumesCurrent = 4 * # of accts')
72 | })))
73 | })
74 |
--------------------------------------------------------------------------------
/test/test-tokens/networks.json:
--------------------------------------------------------------------------------
1 | {
2 | "Migrations": {
3 | "4": {
4 | "events": {},
5 | "links": {},
6 | "address": "0x3fee2f347628b2aea0588c5c6f34e9e3e9d20604",
7 | "transactionHash": "0xcc49cb1456fbc7beaf1278952577ef84ec46c5efd5bf61c410e09444547faa28"
8 | }
9 | },
10 | "TokenCVC": {
11 | "4": {
12 | "events": {},
13 | "links": {},
14 | "address": "0x67Fe0FDf579043de35d9CB2F10C81B63aa8aEef9",
15 | "transactionHash": "0x7a2e9f575b2f58f71a7ec311dbfa873e65fe05b65103a606acc86813f3049336"
16 | }
17 | },
18 | "TokenDAI": {
19 | "4": {
20 | "events": {},
21 | "links": {},
22 | "address": "0x1638578de407719a486db086b36b53750db0199e",
23 | "transactionHash": "0xda8f1054ec6829789b2180a77be255b2ad976517b190862120ae28dc7979362e"
24 | }
25 | },
26 | "TokenGEN": {
27 | "4": {
28 | "events": {},
29 | "links": {},
30 | "address": "0xA1F34744C80e7a9019a5Cd2Bf697F13DF00F9773",
31 | "transactionHash": "0x1619011f643a3a0ecd32d5d9fc348c72060710acbe264c91284d98f296475b58"
32 | }
33 | },
34 | "TokenGRID": {
35 | "4": {
36 | "events": {},
37 | "links": {},
38 | "address": "0xB35E3E3E7A87C2B04DEc49a7b5DA7c1A23a09e64",
39 | "transactionHash": "0x0f7bc9c59a1f2dfe5d61ed600c2bc2473ffaad3a87e01732a9182a06c7f3755f"
40 | }
41 | },
42 | "TokenKNC": {
43 | "4": {
44 | "events": {},
45 | "links": {},
46 | "address": "0xe99211284c54643f4363250b76d078ff0128c8de",
47 | "transactionHash": "0x3670f355266ffeb226b449ea8c05f5c90646b3f3fc45452a52a9a50a9f9f6fc5"
48 | }
49 | },
50 | "TokenMKR": {
51 | "4": {
52 | "events": {},
53 | "links": {},
54 | "address": "0xe315cb6fa401092a7ecc92f05c62d05a974012f4",
55 | "transactionHash": "0x6e6ae370a6ffbb18fd62c26ad02a7b32a67f0a3ccf84fb90397d4c218de80839"
56 | }
57 | },
58 | "TokenOMG": {
59 | "4": {
60 | "events": {},
61 | "links": {},
62 | "address": "0x06713c5fee26237c9de719f42299bccc3d8a2748",
63 | "transactionHash": "0xc8e7871e6e7c8dbfc49b3dd8d8a087cb8fc25f46173d6393401616e16c76d27c"
64 | },
65 | "42": {
66 | "events": {},
67 | "links": {},
68 | "address": "0xde6efd396e18a950b45e24d6225505f48d0c627b",
69 | "transactionHash": "0x4d675f03b12a7c9cba3dc4b63008612f197d6b705e8853c586e9ced0d4844e89"
70 | }
71 | },
72 | "TokenRDN": {
73 | "4": {
74 | "events": {},
75 | "links": {},
76 | "address": "0xb44fac8f17436b2364ff4860f33817c68c6ad6c1",
77 | "transactionHash": "0x44227c36a607b03a4f56f4951d32eab0e9491253037c8f056628e85c6d7fe3e6"
78 | },
79 | "42": {
80 | "events": {},
81 | "links": {},
82 | "address": "0x1f7f270df126ba464228cc8d8203d2768429e085",
83 | "transactionHash": "0xdc8798e1fcc5994649384d3567982eb0df1e77ad5a4a5623ab60f9ee7c0b9b81"
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/contracts/Oracle/Medianizer.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "./DSValue.sol";
4 |
5 |
6 | contract Medianizer is DSValue {
7 | mapping(bytes12 => address) public values;
8 | mapping(address => bytes12) public indexes;
9 | bytes12 public next = bytes12(uint96(1));
10 | uint96 public minimun = 0x1;
11 |
12 | function set(address wat) public auth {
13 | bytes12 nextId = bytes12(uint96(next) + 1);
14 | assert(nextId != 0x0);
15 | set(next, wat);
16 | next = nextId;
17 | }
18 |
19 | function set(bytes12 pos, address wat) public payable note auth {
20 | require(pos != 0x0, "pos cannot be 0x0");
21 | require(wat == address(0) || indexes[wat] == 0, "wat is not defined or it has an index");
22 |
23 | indexes[values[pos]] = bytes12(0); // Making sure to remove a possible existing address in that position
24 |
25 | if (wat != address(0)) {
26 | indexes[wat] = pos;
27 | }
28 |
29 | values[pos] = wat;
30 | }
31 |
32 | function setMin(uint96 min_) public payable note auth {
33 | require(min_ != 0x0, "min cannot be 0x0");
34 | minimun = min_;
35 | }
36 |
37 | function setNext(bytes12 next_) public payable note auth {
38 | require(next_ != 0x0, "next cannot be 0x0");
39 | next = next_;
40 | }
41 |
42 | function unset(bytes12 pos) public {
43 | set(pos, address(0));
44 | }
45 |
46 | function unset(address wat) public {
47 | set(indexes[wat], address(0));
48 | }
49 |
50 | function poke() public {
51 | poke(0);
52 | }
53 |
54 | function poke(bytes32) public payable note {
55 | (val, has) = compute();
56 | }
57 |
58 | function compute() public view returns (bytes32, bool) {
59 | bytes32[] memory wuts = new bytes32[](uint96(next) - 1);
60 | uint96 ctr = 0;
61 | for (uint96 i = 1; i < uint96(next); i++) {
62 | if (values[bytes12(i)] != address(0)) {
63 | (bytes32 wut, bool wuz) = DSValue(values[bytes12(i)]).peek();
64 | if (wuz) {
65 | if (ctr == 0 || wut >= wuts[ctr - 1]) {
66 | wuts[ctr] = wut;
67 | } else {
68 | uint96 j = 0;
69 | while (wut >= wuts[j]) {
70 | j++;
71 | }
72 | for (uint96 k = ctr; k > j; k--) {
73 | wuts[k] = wuts[k - 1];
74 | }
75 | wuts[j] = wut;
76 | }
77 | ctr++;
78 | }
79 | }
80 | }
81 |
82 | if (ctr < minimun)
83 | return (val, false);
84 |
85 | bytes32 value;
86 | if (ctr % 2 == 0) {
87 | uint128 val1 = uint128(uint(wuts[(ctr / 2) - 1]));
88 | uint128 val2 = uint128(uint(wuts[ctr / 2]));
89 | value = bytes32(uint256(wdiv(hadd(val1, val2), 2 ether)));
90 | } else {
91 | value = wuts[(ctr - 1) / 2];
92 | }
93 |
94 | return (value, true);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@gnosis.pm/dx-contracts",
3 | "version": "2.0.0",
4 | "description": "DutchX - Gnosis Dutch Auction Trading Platform. This npm package provides all smartcontracts used in the project",
5 | "scripts": {
6 | "rpc": "ganache-cli -d --mnemonic 'candy maple cake sugar pudding cream honey rich smooth crumble sweet treat' --defaultBalanceEther '500000000000000000000'",
7 | "preversion": "npm run restore",
8 | "test": "npm run solium && npx truffle test test/*.spec.js -s",
9 | "coverage": "npx solidity-coverage",
10 | "truffle": "npx truffle",
11 | "networks-extract": "node src/extract_network_info.js",
12 | "networks-inject": "node src/inject_network_info.js",
13 | "networks-reset": "mkdir -p build/contracts && npx truffle networks --clean && npm run networks-inject",
14 | "networks": "npx truffle networks",
15 | "compile-todo": "eslint --fix . && eslint . && npx truffle compile",
16 | "compile": "npx truffle compile",
17 | "restore": "rm -rf build && npm run compile && npm run networks-reset",
18 | "migrate": "npx truffle migrate",
19 | "lint": "eslint .",
20 | "solium": "solium --dir ./contracts/",
21 | "wrap-eth": "npx truffle exec src/truffle/wrap-eth.js",
22 | "set-weth-allowance": "npx truffle exec src/truffle/set-weth-allowance.js",
23 | "deposit-weth": "npx truffle exec src/truffle/deposit-weth.js",
24 | "add-token-pairs": "npx truffle exec src/truffle/add-token-pairs.js",
25 | "approve-tokens": "npx truffle exec src/truffle/approve-tokens.js",
26 | "unlock-mgn": "npx truffle exec src/truffle/unlock-mgn.js",
27 | "claim-unlocked-mgn": "npx truffle exec src/truffle/claim-unlocked-mgn.js",
28 | "set-auctioneer": "npx truffle exec src/truffle/set-auctioneer.js",
29 | "get-abi-encoded-params": "npx truffle exec src/truffle/get-abi-encoded-params.js",
30 | "prettier": "prettier --write --tab-width 4 --print-width 120 '**/*.sol'",
31 | "install": "cd $INIT_CWD && npm explore truffle -- npm install solc@0.5.2"
32 | },
33 | "repository": {
34 | "type": "git",
35 | "url": "https://github.com/gnosis/dx-contracts.git"
36 | },
37 | "author": "Gnosis",
38 | "license": "LGPL-3.0",
39 | "dependencies": {
40 | "@gnosis.pm/gno-token": "^2.0.0",
41 | "@gnosis.pm/owl-token": "^2.0.0",
42 | "@gnosis.pm/util-contracts": "^2.0.0"
43 | },
44 | "devDependencies": {
45 | "bignumber.js": "^5.0.0",
46 | "chai": "^4.2.0",
47 | "coveralls": "^3.0.3",
48 | "dotenv": "^8.0.0",
49 | "eslint": "^5.14.1",
50 | "eslint-config-standard": "^12.0.0",
51 | "eslint-plugin-import": "^2.14.0",
52 | "eslint-plugin-node": "^9.1.0",
53 | "eslint-plugin-promise": "^4.0.1",
54 | "eslint-plugin-standard": "^4.0.0",
55 | "ethereumjs-abi": "^0.6.6",
56 | "minimist": "^1.2.0",
57 | "openzeppelin-test-helpers": "^0.4.0",
58 | "prettier": "^1.16.4",
59 | "prettier-plugin-solidity-refactor": "^1.0.0-alpha.14",
60 | "solc": "0.5.2",
61 | "solidity-coverage": "^0.5.11",
62 | "solium": "^1.2.4",
63 | "truffle": "^5.0.5",
64 | "truffle-contract": "^4.0.17",
65 | "truffle-flattener": "^1.3.0",
66 | "truffle-hdwallet-provider": "1.0.9",
67 | "yargs": "^13.2.4"
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/migrations-truffle-5/3_deploy_price_feed.js:
--------------------------------------------------------------------------------
1 | const DEFAULT_ETH_USD_PRICE = process.env.ETH_USD_PRICE || 1100 // 500 USD/ETH
2 | const DEFAULT_FEED_EXPIRE_PERIOD_DAYS =
3 | process.env.FEED_EXPIRE_PERIOD_DAYS || 365 // 1 year
4 |
5 | async function migrate ({
6 | artifacts,
7 | deployer,
8 | network,
9 | accounts,
10 | web3,
11 | ethUsdPrice = DEFAULT_ETH_USD_PRICE,
12 | feedExpirePeriodDays = DEFAULT_FEED_EXPIRE_PERIOD_DAYS
13 | }) {
14 | const Medianizer = artifacts.require('Medianizer')
15 | const PriceOracleInterface = artifacts.require('PriceOracleInterface')
16 | const PriceFeed = artifacts.require('PriceFeed')
17 |
18 | const medianizerAddress = getMedianizerAddress(Medianizer)
19 | const account = accounts[0]
20 | if (!medianizerAddress) {
21 | console.log(
22 | `Deploying Maker Dao feed contracts, because they weren published in network "${network}" yet`
23 | )
24 | // Deployment of PriceFeedInfrastructure
25 |
26 | console.log('Deploy PriceFeed')
27 | await deployer.deploy(PriceFeed)
28 | const priceFeed = await PriceFeed.deployed()
29 |
30 | console.log('Deploy Medianizer')
31 | await deployer.deploy(Medianizer)
32 | const medianizer = await Medianizer.deployed()
33 |
34 | console.log('Deploy PriceOracleInterface:')
35 | console.log(' - account: %s', account)
36 | console.log(' - medianizer address: %s', medianizer.address)
37 | await deployer.deploy(PriceOracleInterface, account, medianizer.address)
38 |
39 | console.log('Set price feed for medianizer:')
40 | console.log(' - price feed address: %s', PriceFeed.address)
41 | await medianizer.set(PriceFeed.address)
42 |
43 | const now = await getTime(web3)
44 | const expireTime = now + feedExpirePeriodDays * 24 * 60 * 60
45 |
46 | console.log('Post price for price feed:')
47 | console.log(' - ETH-USD: %s', ethUsdPrice)
48 | console.log(' - Expire time: %s', new Date(expireTime * 1000))
49 | console.log(' - Medianizer address: %s', medianizer.address)
50 |
51 | const BN = web3.utils.BN
52 | const ethUsdPriceWei = web3.utils.toWei(new BN(ethUsdPrice))
53 | await priceFeed.post(ethUsdPriceWei, expireTime, medianizer.address)
54 | } else {
55 | console.log(
56 | `No need to deploy the Medianizer. Using ${medianizerAddress} as the Medianizer address`
57 | )
58 |
59 | console.log('Deploy PriceOracleInterface:')
60 | console.log(' - account: %s', account)
61 | console.log(' - medianizer address: %s', medianizerAddress)
62 | await deployer.deploy(PriceOracleInterface, account, medianizerAddress)
63 | }
64 | }
65 |
66 | function getMedianizerAddress (Medianizer) {
67 | try {
68 | return Medianizer.address
69 | } catch (error) {
70 | // Medianizer.address throw an error if there's no config address
71 | // As a result, only development should be deploying this contracts
72 | return null
73 | }
74 | }
75 |
76 | async function getTime (web3) {
77 | return new Promise((resolve, reject) => {
78 | web3.eth.getBlock('latest', (err, block) => {
79 | if (err) {
80 | return reject(err)
81 | } else {
82 | resolve(block.timestamp)
83 | }
84 | })
85 | })
86 | }
87 |
88 | module.exports = migrate
89 |
--------------------------------------------------------------------------------
/contracts/ForTestingOnly/SubStandardToken.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 | import "./BadToken.sol";
3 | import "@gnosis.pm/util-contracts/contracts/Math.sol";
4 | import "@gnosis.pm/util-contracts/contracts/Proxy.sol";
5 | import {StandardTokenData} from "@gnosis.pm/util-contracts/contracts/GnosisStandardToken.sol";
6 |
7 |
8 | /// @title Standard token contract with overflow protection
9 | contract SubStandardToken is BadToken, StandardTokenData {
10 | using GnosisMath for *;
11 |
12 | /*
13 | * Public functions
14 | */
15 | /// @dev Transfers sender's tokens to a given address. Returns success
16 | /// @param to Address of token receiver
17 | /// @param value Number of tokens to transfer
18 | /// @return Was transfer successful?
19 | function transfer(address to, uint value)
20 | public
21 | {
22 | if ( !balances[msg.sender].safeToSub(value) ||
23 | !balances[to].safeToAdd(value))
24 | return;
25 | balances[msg.sender] -= value;
26 | balances[to] += value;
27 | emit Transfer(msg.sender, to, value);
28 | }
29 |
30 | /// @dev Allows allowed third party to transfer tokens from one address to another. Returns success
31 | /// @param from Address from where tokens are withdrawn
32 | /// @param to Address to where tokens are sent
33 | /// @param value Number of tokens to transfer
34 | /// @return Was transfer successful?
35 | function transferFrom(address from, address to, uint value)
36 | public
37 | {
38 | if ( !balances[from].safeToSub(value) ||
39 | !allowances[from][msg.sender].safeToSub(value) ||
40 | !balances[to].safeToAdd(value))
41 | return;
42 | balances[from] -= value;
43 | allowances[from][msg.sender] -= value;
44 | balances[to] += value;
45 | emit Transfer(from, to, value);
46 | }
47 |
48 | /// @dev Sets approved amount of tokens for spender. Returns success
49 | /// @param spender Address of allowed account
50 | /// @param value Number of approved tokens
51 | /// @return Was approval successful?
52 | function approve(address spender, uint value)
53 | public
54 | returns (bool)
55 | {
56 | allowances[msg.sender][spender] = value;
57 | emit Approval(msg.sender, spender, value);
58 | return true;
59 | }
60 |
61 | /// @dev Returns number of allowed tokens for given address
62 | /// @param owner Address of token owner
63 | /// @param spender Address of token spender
64 | /// @return Remaining allowance for spender
65 | function allowance(address owner, address spender)
66 | public
67 | view
68 | returns (uint)
69 | {
70 | return allowances[owner][spender];
71 | }
72 |
73 | /// @dev Returns number of tokens owned by given address
74 | /// @param owner Address of token owner
75 | /// @return Balance of owner
76 | function balanceOf(address owner)
77 | public
78 | view
79 | returns (uint)
80 | {
81 | return balances[owner];
82 | }
83 |
84 | /// @dev Returns total supply of tokens
85 | /// @return Total supply
86 | function totalSupply()
87 | public
88 | view
89 | returns (uint)
90 | {
91 | return totalTokens;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/deploy-mainnet.txt:
--------------------------------------------------------------------------------
1 | yarn run v1.12.3
2 | $ npx truffle migrate --network mainnet
3 | Create HDWalletProvider
4 | Using gas limit: 6721.975 K
5 | Using gas price: 5 Gwei
6 | Optimizer enabled: true
7 | Sign transactions using: Private Key
8 | Using private key
9 | Truffle 4
10 | Using network 'mainnet'.
11 |
12 | Running migration: 1_initial_migration.js
13 | Deploying Migrations...
14 | [HDWalletProvider] Using nonce: 255
15 | ... 0x548baa2a1111fd30f432a09d0843a7fd6ac14e5b2751193d30623eee55cbe468
16 | Migrations: 0x135d8de3b5addb0232cd1f59002db7cf0b8b6e65
17 | Saving artifacts...
18 | Running migration: 2_DEV_migrate_dependencies.js
19 | Not in development, so nothing to do. Current network is mainnet
20 | Saving artifacts...
21 | Running migration: 3_DEV-deploy_price_feed.js
22 | No need to deploy the Medianizer. Using 0x729D19f657BD0614b4985Cf1D82531c67569197B as the Medianizer address
23 | Deploying PriceOracleInterface with owner: 0xb1f919db227048a1a45883138b9d12b9ef03df25
24 | Replacing PriceOracleInterface...
25 | [HDWalletProvider] Using nonce: 256
26 | ... 0x6b00382330116132a36bc755fd5f86a9e1ab1d3d00f5a61a62be5cfcfaf788b3
27 | PriceOracleInterface: 0xef6e5fc1a796db0a9a848eb1bb1156a9648f5ac6
28 | Saving artifacts...
29 | Running migration: 4_deploy_FRT.js
30 | Running step...
31 | Replacing TokenFRT...
32 | [HDWalletProvider] Using nonce: 257
33 | ... 0xdb55ddbb761be09782f59fa82d9a2a77f79d8dfda8e76a77c3040b6c3c5250f2
34 | TokenFRT: 0xbe4eecb9ebc040183a95f22a74a5763d442dfbb5
35 | Deploying TokenFRTProxy with ACCOUNT ==> 0xb1f919db227048a1a45883138b9d12b9ef03df25
36 | Replacing TokenFRTProxy...
37 | [HDWalletProvider] Using nonce: 258
38 | ... 0x274d24b7c8d129e3af23fba6c5a7b6dcf9b88566974a0708f772531dda63ccfe
39 | TokenFRTProxy: 0x80f222a749a2e18eb7f676d371f19ad7efeee3b7
40 | Saving artifacts...
41 | Running migration: 5_deploy_DX.js
42 | Running step...
43 | Replacing DutchExchange...
44 | [HDWalletProvider] Using nonce: 259
45 | ... 0xdfd7c80850e86ba0e8ecbe51267da31ed627bfeadec70e886069cf599de88c42
46 | DutchExchange: 0x2bae491b065032a76be1db9e9ecf5738afae203e
47 | Replacing DutchExchangeProxy...
48 | [HDWalletProvider] Using nonce: 260
49 | ... 0xb6061e32145f4b3a1b6864f0ee9d4fbdd13304afa44a6b98bdf03c05af01586f
50 | DutchExchangeProxy: 0xb9812e2fa995ec53b5b6df34d21f9304762c5497
51 | Saving artifacts...
52 | Running migration: 6_setup_DX.js
53 | Running step...
54 | Setup DX with:
55 | Owner: 0xb1f919db227048a1a45883138b9d12b9ef03df25
56 | OWL address: 0x1a5f9352af8af974bfc03399e3767df6370d82e4
57 | FRT address: 0x80f222a749a2e18eb7f676d371f19ad7efeee3b7
58 | WETH address: 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
59 | Price Oracle address: 0xef6e5fc1a796db0a9a848eb1bb1156a9648f5ac6
60 | Threshold for new token pair: 10000
61 | Threshold for auction to start: 1000
62 | [HDWalletProvider] Using nonce: 261
63 | ... 0xbe5c43f609568a4e4f4639206a520c0d60175f03a15bcb9fe245bc5da035f83a
64 | Deploy DutchExchangeHelper:
65 | Replacing DutchExchangeHelper...
66 | [HDWalletProvider] Using nonce: 262
67 | ... 0x2bf350595f8f1ebc9d8d44111900c30a6d7d46ea43162551bdcda765b2d7af5f
68 | DutchExchangeHelper: 0x64832950abccaa3d02ab8eb09aa058d789f5bb6a
69 | Saving artifacts...
70 | Running migration: 7_set_DX_as_FRT_minter.js
71 | Running step...
72 | [HDWalletProvider] Using nonce: 263
73 | ... 0x0fcf596cf41b2446d9cc918bdae3d322766396550ba5cbd2f34307af1fec7e2e
74 | Saving artifacts...
75 | Done in 627.40s.
76 |
--------------------------------------------------------------------------------
/test/trufflescripts/buy_order.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | const {
3 | deployed,
4 | getTokenDeposits,
5 | getAccountsStatsForTokenPairAuction,
6 | getExchangeStatsForTokenPair,
7 | postBuyOrder,
8 | } = require('./utils/contracts')(artifacts)
9 | const argv = require('minimist')(process.argv.slice(2), { string: 'a' })
10 |
11 | /**
12 | * truffle exec test/trufflescripts/buy_order.js
13 | * to post a buy order to token pair auction as the buyer
14 | * @flags:
15 | * -n for a specific amount of buyToken
16 | * --pair token pair auction, eth,gno by default
17 | * --seller as the seller
18 | * -a as the given account
19 | * --next to the next auction (lastAuctionIndex + 1)
20 | */
21 |
22 |
23 | module.exports = async () => {
24 | const { eth, gno } = await deployed
25 | const availableTokens = { eth, gno }
26 |
27 | const [sell, buy] = argv.pair ? argv.pair.split(',') : ['eth', 'gno']
28 | let sellToken = availableTokens[sell.toLowerCase()] || eth
29 | let buyToken = availableTokens[buy.toLowerCase()] || gno
30 |
31 | if (!sellToken || !buyToken) {
32 | console.warn(`Token ${!sellToken || !buyToken} is not available`)
33 | return
34 | }
35 |
36 | if (argv.n === undefined) {
37 | console.warn('No amount provided')
38 | return
39 | }
40 |
41 | sellToken = sellToken.address
42 | buyToken = buyToken.address
43 |
44 | const sellTokenName = sell ? sell.toUpperCase() : 'ETH'
45 | const buyTokenName = buy ? buy.toUpperCase() : 'GNO'
46 |
47 | let account
48 | if (argv.a) account = argv.a
49 | else if (argv.seller)[, account] = web3.eth.accounts
50 | else {
51 | [, , account] = web3.eth.accounts
52 | }
53 |
54 | let { [buyTokenName]: buyTokenDeposit = 0 } = await getTokenDeposits(account)
55 |
56 | if (buyTokenDeposit < argv.n) {
57 | console.log(`Account's deposit is ${argv.n - buyTokenDeposit} tokens short to submit this order`)
58 | return
59 | }
60 |
61 | const { latestAuctionIndex } = await getExchangeStatsForTokenPair({ sellToken, buyToken })
62 |
63 | const index = argv.next ? latestAuctionIndex + 1 : latestAuctionIndex
64 |
65 | let [{ buyVolume }, { [account]: { buyerBalance } }] = await Promise.all([
66 | getExchangeStatsForTokenPair({ sellToken, buyToken }),
67 | getAccountsStatsForTokenPairAuction({ sellToken, buyToken, index, accounts: [account] }),
68 | ])
69 |
70 | console.log(`Auction ${sellTokenName} -> ${buyTokenName} index ${index} (${argv.next ? 'next' : 'current'})
71 | was:
72 | buyVolume:\t${buyVolume}
73 | buyerBalance:\t${buyerBalance} in auction
74 | buyerDeposit:\t${buyTokenDeposit} ${buyTokenName}
75 | `)
76 |
77 |
78 | console.log(`
79 | Posting order for ${argv.n} ${buyTokenName}
80 | `)
81 |
82 | const tx = await postBuyOrder(account, { sellToken, buyToken, index, amount: argv.n })
83 | if (!tx) return
84 |
85 | [
86 | { [buyTokenName]: buyTokenDeposit = 0 },
87 | { buyVolume },
88 | { [account]: { buyerBalance } },
89 | ] = await Promise.all([
90 | getTokenDeposits(account),
91 | getExchangeStatsForTokenPair({ sellToken, buyToken }),
92 | getAccountsStatsForTokenPairAuction({ sellToken, buyToken, index, accounts: [account] }),
93 | ])
94 |
95 |
96 | console.log(` now:
97 | buyVolume:\t${buyVolume}
98 | buyerBalance:\t${buyerBalance} in auction
99 | buyerDeposit:\t${buyTokenDeposit} ${buyTokenName}
100 | `)
101 | }
102 |
--------------------------------------------------------------------------------
/src/migrations-truffle-5/6_setup_DX.js:
--------------------------------------------------------------------------------
1 | const DEFAULT_THRESHOLD_NEW_TOKEN_PAIR_USD = 10000 // 10K USD
2 | const DEFAULT_THRESHOLD_AUCTION_START_USD = 1000 // 1K USD
3 |
4 | async function migrate ({
5 | artifacts,
6 | deployer,
7 | network,
8 | accounts,
9 | web3,
10 | thresholdNewTokenPairUsd = DEFAULT_THRESHOLD_NEW_TOKEN_PAIR_USD,
11 | thresholdAuctionStartUsd = DEFAULT_THRESHOLD_AUCTION_START_USD
12 | }) {
13 | const owner = accounts[0]
14 | const TokenFRT = artifacts.require('TokenFRT')
15 | const TokenFRTProxy = artifacts.require('TokenFRTProxy')
16 | const DutchExchange = artifacts.require('DutchExchange')
17 | const DutchExchangeProxy = artifacts.require('DutchExchangeProxy')
18 | const PriceOracleInterface = artifacts.require('PriceOracleInterface')
19 | const DutchExchangeHelper = artifacts.require('DutchExchangeHelper')
20 |
21 | const {
22 | EtherToken,
23 | TokenGNO,
24 | TokenOWLProxy
25 | } = _getDependencies(artifacts, network, deployer)
26 |
27 | // Ensure the folowing contracts are deployed:
28 | // - Tokens: GNO, OWL, WETH, MGN
29 | // - PriceOracleInterface
30 | // - DX contract and its proxy
31 | await TokenGNO.deployed()
32 | const tokenOWLProxy = await TokenOWLProxy.deployed()
33 | const etherToken = await EtherToken.deployed()
34 |
35 | const tokenFRT = await TokenFRT.at(TokenFRTProxy.address)
36 |
37 | const priceOracleInterface = await PriceOracleInterface.deployed()
38 | const dxProxy = await DutchExchangeProxy.deployed()
39 | await DutchExchange.deployed()
40 | const dx = await DutchExchange.at(dxProxy.address)
41 |
42 | const frtAddress = tokenFRT.address
43 | const owlAddress = tokenOWLProxy.address
44 | const wethAddress = etherToken.address
45 | const oracleAddress = priceOracleInterface.address
46 |
47 | console.log('Setup DX with:')
48 | console.log('\t Owner: %s', owner)
49 | console.log('\t OWL address: %s', owlAddress)
50 | console.log('\t FRT address: %s', frtAddress)
51 | console.log('\t WETH address: %s', wethAddress)
52 | console.log('\t Price Oracle address: %s', oracleAddress)
53 | console.log('\t Threshold for new token pair: %s', thresholdNewTokenPairUsd)
54 | console.log('\t Threshold for auction to start: %s', thresholdAuctionStartUsd)
55 |
56 | const BN = web3.utils.BN
57 | await dx.setupDutchExchange(
58 | frtAddress,
59 | owlAddress,
60 | owner,
61 | wethAddress,
62 | oracleAddress,
63 | web3.utils.toWei(
64 | new BN(thresholdNewTokenPairUsd)
65 | ),
66 | web3.utils.toWei(
67 | new BN(thresholdAuctionStartUsd)
68 | )
69 | )
70 |
71 | console.log('Deploy DutchExchangeHelper:')
72 | await deployer.deploy(DutchExchangeHelper, DutchExchangeProxy.address)
73 | }
74 |
75 | function _getDependencies (artifacts, network, deployer) {
76 | let EtherToken, TokenGNO, TokenOWLProxy
77 | if (network === 'development') {
78 | EtherToken = artifacts.require('EtherToken')
79 | TokenGNO = artifacts.require('TokenGNO')
80 | TokenOWLProxy = artifacts.require('TokenOWLProxy')
81 | } else {
82 | const contract = require('truffle-contract')
83 | EtherToken = contract(require('@gnosis.pm/util-contracts/build/contracts/EtherToken'))
84 | EtherToken.setProvider(deployer.provider)
85 | TokenGNO = contract(require('@gnosis.pm/gno-token/build/contracts/TokenGNO'))
86 | TokenGNO.setProvider(deployer.provider)
87 | TokenOWLProxy = contract(require('@gnosis.pm/owl-token/build/contracts/TokenOWLProxy'))
88 | TokenOWLProxy.setProvider(deployer.provider)
89 | }
90 |
91 | return { EtherToken, TokenGNO, TokenOWLProxy }
92 | }
93 |
94 | module.exports = migrate
95 |
--------------------------------------------------------------------------------
/src/migrations-truffle-4/6_setup_DX.js:
--------------------------------------------------------------------------------
1 | const DEFAULT_THRESHOLD_NEW_TOKEN_PAIR_USD = 10000 // 10K USD
2 | const DEFAULT_THRESHOLD_AUCTION_START_USD = 1000 // 1K USD
3 |
4 | function migrate ({
5 | artifacts,
6 | deployer,
7 | network,
8 | accounts,
9 | thresholdNewTokenPairUsd = DEFAULT_THRESHOLD_NEW_TOKEN_PAIR_USD,
10 | thresholdAuctionStartUsd = DEFAULT_THRESHOLD_AUCTION_START_USD
11 | }) {
12 | const TokenFRT = artifacts.require('TokenFRT')
13 | const TokenFRTProxy = artifacts.require('TokenFRTProxy')
14 | const DutchExchange = artifacts.require('DutchExchange')
15 | const DutchExchangeProxy = artifacts.require('DutchExchangeProxy')
16 | const PriceOracleInterface = artifacts.require('PriceOracleInterface')
17 | const DutchExchangeHelper = artifacts.require('DutchExchangeHelper')
18 |
19 | const {
20 | EtherToken,
21 | TokenGNO,
22 | TokenOWLProxy
23 | } = _getDependencies(artifacts, network, deployer)
24 |
25 | return deployer
26 | // Ensure the folowing contracts are deployed:
27 | // Tokens: GNO, OWL, WETH
28 | // PriceOracleInterface
29 | // DX contract and its proxy
30 | .then(() => Promise.all([
31 | TokenFRT.deployed(),
32 | EtherToken.deployed(),
33 | TokenGNO.deployed(),
34 | TokenOWLProxy.deployed(),
35 | PriceOracleInterface.deployed(),
36 | DutchExchange.deployed(),
37 | DutchExchangeProxy.deployed()
38 | ]))
39 | .then(() => {
40 | const dx = DutchExchange.at(DutchExchangeProxy.address)
41 | const owner = accounts[0]
42 | const frt = TokenFRT.at(TokenFRTProxy.address)
43 | const frtAddress = frt.address
44 | const owlAddress = TokenOWLProxy.address
45 | const wethAddress = EtherToken.address
46 | const oracleAddress = PriceOracleInterface.address
47 |
48 | console.log('Setup DX with:')
49 | console.log('\t Owner: %s', owner)
50 | console.log('\t OWL address: %s', owlAddress)
51 | console.log('\t FRT address: %s', frtAddress)
52 | console.log('\t WETH address: %s', wethAddress)
53 | console.log('\t Price Oracle address: %s', oracleAddress)
54 | console.log('\t Threshold for new token pair: %s', thresholdNewTokenPairUsd)
55 | console.log('\t Threshold for auction to start: %s', thresholdAuctionStartUsd)
56 |
57 | return dx.setupDutchExchange(
58 | frtAddress,
59 | owlAddress,
60 | owner,
61 | wethAddress,
62 | oracleAddress,
63 | thresholdNewTokenPairUsd * 1e18,
64 | thresholdAuctionStartUsd * 1e18
65 | )
66 | })
67 | // Deploy the helper
68 | .then(() => {
69 | console.log('Deploy DutchExchangeHelper:')
70 | return deployer.deploy(DutchExchangeHelper, DutchExchangeProxy.address)
71 | })
72 | }
73 |
74 | function _getDependencies (artifacts, network, deployer) {
75 | let EtherToken, TokenGNO, TokenOWLProxy
76 | if (network === 'development') {
77 | EtherToken = artifacts.require('EtherToken')
78 | TokenGNO = artifacts.require('TokenGNO')
79 | TokenOWLProxy = artifacts.require('TokenOWLProxy')
80 | } else {
81 | const contract = require('truffle-contract')
82 | EtherToken = contract(require('@gnosis.pm/util-contracts/build/contracts/EtherToken'))
83 | EtherToken.setProvider(deployer.provider)
84 | TokenGNO = contract(require('@gnosis.pm/gno-token/build/contracts/TokenGNO'))
85 | TokenGNO.setProvider(deployer.provider)
86 | TokenOWLProxy = contract(require('@gnosis.pm/owl-token/build/contracts/TokenOWLProxy'))
87 | TokenOWLProxy.setProvider(deployer.provider)
88 | }
89 |
90 | return { EtherToken, TokenGNO, TokenOWLProxy }
91 | }
92 |
93 | module.exports = migrate
94 |
--------------------------------------------------------------------------------
/test/trufflescripts/sell_order.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | const {
3 | deployed,
4 | getTokenDeposits,
5 | getAccountsStatsForTokenPairAuction,
6 | getExchangeStatsForTokenPair,
7 | postSellOrder,
8 | } = require('./utils/contracts')(artifacts)
9 | const argv = require('minimist')(process.argv.slice(2), { string: 'a' })
10 |
11 | /**
12 | * truffle exec test/trufflescripts/sell_order.js
13 | * to post a sell order to token pair auction as the seller
14 | * @flags:
15 | * -n for a specific amount of sellToken
16 | * --pair token pair auction, eth,gno by default
17 | * --buyer as the buyer
18 | * -a as the given account
19 | * --next to the next auction (lastAuctionIndex + 1)
20 | */
21 |
22 |
23 | module.exports = async () => {
24 | const { eth, gno } = await deployed
25 | const availableTokens = { eth, gno }
26 |
27 | const [sell, buy] = argv.pair ? argv.pair.split(',') : ['eth', 'gno']
28 | let sellToken = availableTokens[sell.toLowerCase()] || eth
29 | let buyToken = availableTokens[buy.toLowerCase()] || gno
30 |
31 | if (!sellToken || !buyToken) {
32 | console.warn(`Token ${!sellToken || !buyToken} is not available`)
33 | return
34 | }
35 |
36 | if (argv.n === undefined) {
37 | console.warn('No amount provided')
38 | return
39 | }
40 |
41 | sellToken = sellToken.address
42 | buyToken = buyToken.address
43 |
44 | const sellTokenName = sell ? sell.toUpperCase() : 'ETH'
45 | const buyTokenName = buy ? buy.toUpperCase() : 'GNO'
46 |
47 | let account
48 | if (argv.a) account = argv.a
49 | else if (argv.buyer)[, , account] = web3.eth.accounts
50 | else {
51 | [, account] = web3.eth.accounts
52 | }
53 |
54 | let { [sellTokenName]: sellTokenDeposit = 0 } = await getTokenDeposits(account)
55 |
56 | if (sellTokenDeposit < argv.n) {
57 | console.log(`Account's deposit is ${argv.n - sellTokenDeposit} tokens short to submit this order`)
58 | return
59 | }
60 |
61 | const { latestAuctionIndex } = await getExchangeStatsForTokenPair({ sellToken, buyToken })
62 |
63 | const index = argv.next ? latestAuctionIndex + 1 : latestAuctionIndex
64 |
65 | let [{ sellVolumeCurrent, sellVolumeNext }, { [account]: { sellerBalance } }] = await Promise.all([
66 | getExchangeStatsForTokenPair({ sellToken, buyToken }),
67 | getAccountsStatsForTokenPairAuction({ sellToken, buyToken, index, accounts: [account] }),
68 | ])
69 |
70 | console.log(`Auction ${sellTokenName} -> ${buyTokenName} index ${index} (${argv.next ? 'next' : 'current'})
71 | was:
72 | sellVolumeCurrent:\t${sellVolumeCurrent}
73 | sellVolumeNext:\t${sellVolumeNext}
74 | sellerBalance:\t${sellerBalance} in auction
75 | sellerDeposit:\t${sellTokenDeposit} ${sellTokenName}
76 | `)
77 |
78 |
79 | console.log(`
80 | Posting order for ${argv.n} ${sellTokenName}
81 | `)
82 |
83 | const tx = await postSellOrder(account, { sellToken, buyToken, index, amount: argv.n })
84 | if (!tx) return
85 |
86 | [
87 | { [sellTokenName]: sellTokenDeposit = 0 },
88 | { sellVolumeCurrent, sellVolumeNext },
89 | { [account]: { sellerBalance } },
90 | ] = await Promise.all([
91 | getTokenDeposits(account),
92 | getExchangeStatsForTokenPair({ sellToken, buyToken }),
93 | getAccountsStatsForTokenPairAuction({ sellToken, buyToken, index, accounts: [account] }),
94 | ])
95 |
96 |
97 | console.log(` now:
98 | sellVolumeCurrent:\t${sellVolumeCurrent}
99 | sellVolumeNext:\t${sellVolumeNext}
100 | sellerBalance:\t${sellerBalance} in auction
101 | sellerDeposit:\t${sellTokenDeposit} ${sellTokenName}
102 | `)
103 | }
104 |
--------------------------------------------------------------------------------
/test/trufflescripts/claim_funds.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | const {
3 | deployed,
4 | getTokenDeposits,
5 | getAccountsStatsForTokenPairAuction,
6 | getExchangeStatsForTokenPair,
7 | claimBuyerFunds,
8 | claimSellerFunds,
9 | getUnclaimedBuyerFunds,
10 | getUnclaimedSellerFunds,
11 | } = require('./utils/contracts')(artifacts)
12 | const argv = require('minimist')(process.argv.slice(2), { string: 'a' })
13 |
14 | /**
15 | * truffle exec test/trufflescripts/claim_funds.js
16 | * to claim funds for the current auction for both seller and buyer,
17 | * from auction's sellerBalances and buyerBalances respectively
18 | * @flags:
19 | * --seller sellerBalance for seller only
20 | * --buyer buyerBalance for buyer only
21 | * -a seller|buyer|master| for the given address
22 | * -i for auction with given index
23 | * --last for last auction
24 | */
25 |
26 | module.exports = async () => {
27 | const { eth: sellToken, gno: buyToken } = await deployed
28 | const sellTokenName = 'ETH'
29 | const buyTokenName = 'GNO'
30 |
31 | let index = argv.i !== undefined ? argv.i
32 | : (await getExchangeStatsForTokenPair({ sellToken, buyToken })).latestAuctionIndex
33 | if (argv.i === undefined && argv.last) index -= 1
34 | // eslint-disable-next-line
35 | let [master, seller, buyer] = web3.eth.accounts
36 |
37 | if (argv.a === 'seller') buyer = seller
38 | else if (argv.a === 'buyer') seller = buyer
39 | else if (argv.a === 'master') seller = buyer = master
40 | else if (argv.a) seller = buyer = argv.a
41 |
42 | const getStats = async (account, role) => {
43 | const [
44 | { [account]: { sellerBalance, buyerBalance, claimedAmount } },
45 | { [sellTokenName]: sellTokenDeposit = 0, [buyTokenName]: buyTokenDeposit = 0 },
46 | [unclaimedAmount] = [],
47 | ] = await Promise.all([
48 | getAccountsStatsForTokenPairAuction({ sellToken, buyToken, index, accounts: [account] }),
49 | getTokenDeposits(account),
50 | (role === 'seller' ? getUnclaimedSellerFunds : getUnclaimedBuyerFunds)({ sellToken, buyToken, user: account, index }),
51 | ])
52 |
53 | return { sellerBalance, buyerBalance, claimedAmount, sellTokenDeposit, buyTokenDeposit, unclaimedAmount }
54 | }
55 |
56 | const printSeller = async () => {
57 | let { sellerBalance, claimedAmount, unclaimedAmount, sellTokenDeposit } = await getStats(seller, 'seller')
58 |
59 | console.log(`
60 | Seller\tbalance\tunclaimed \tclaimed\tdeposit
61 | was:\t${sellerBalance}\t${unclaimedAmount}\t\t${claimedAmount}\t${sellTokenDeposit}`)
62 |
63 | await claimSellerFunds({ sellToken, buyToken, user: seller, index });
64 |
65 | ({ sellerBalance, claimedAmount, unclaimedAmount, sellTokenDeposit } = await getStats(seller, 'seller'))
66 |
67 | console.log(` is:\t\t${sellerBalance}\t${unclaimedAmount}\t\t${claimedAmount}\t${sellTokenDeposit}`)
68 | }
69 |
70 | const printBuyer = async () => {
71 | let { buyerBalance, claimedAmount, unclaimedAmount, buyTokenDeposit } = await getStats(buyer, 'buyer')
72 |
73 | console.log(`
74 | Buyer\tbalance\tunclaimed \tclaimed\tdeposit
75 | was:\t${buyerBalance}\t${unclaimedAmount}\t\t${claimedAmount}\t${buyTokenDeposit}
76 | `)
77 |
78 | await claimBuyerFunds({ sellToken, buyToken, user: buyer, index });
79 |
80 | ({ buyerBalance, claimedAmount, unclaimedAmount, buyTokenDeposit } = await getStats(buyer, 'buyer'))
81 |
82 | console.log(` is:\t\t${buyerBalance}\t${unclaimedAmount}\t\t${claimedAmount}\t${buyTokenDeposit}`)
83 | }
84 |
85 | console.log(`in auction ${index}`)
86 |
87 | if (argv.seller) {
88 | await printSeller()
89 | } else if (argv.buyer) {
90 | await printBuyer()
91 | } else {
92 | await printSeller()
93 | await printBuyer()
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/deploy-kovan.txt:
--------------------------------------------------------------------------------
1 | yarn run v1.12.3
2 | $ npx truffle migrate --network kovan --reset
3 | Create HDWalletProvider
4 | Using gas limit: 6721.975 K
5 | Using gas price: 5 Gwei
6 | Optimizer enabled: true
7 | Sign transactions using: Private Key
8 | Using private key
9 | Truffle 4
10 | Compiling ./contracts/ForTestingOnly/BadToken.sol...
11 | Compiling ./contracts/ForTestingOnly/SubStandardToken.sol...
12 | Compiling ./contracts/ForTestingOnly/TokenGNO.sol...
13 | Compiling @gnosis.pm/util-contracts/contracts/GnosisStandardToken.sol...
14 | Compiling @gnosis.pm/util-contracts/contracts/Math.sol...
15 | Compiling @gnosis.pm/util-contracts/contracts/Proxy.sol...
16 | Compiling @gnosis.pm/util-contracts/contracts/Token.sol...
17 | Writing artifacts to ./build/contracts
18 |
19 | Using network 'kovan'.
20 |
21 | Running migration: 1_initial_migration.js
22 | Deploying Migrations...
23 | [HDWalletProvider] Using nonce: 356
24 | ... 0xbffe78bd757c5fe67f277681fb0849669c1a3998a9c19495f442a836f8ede07c
25 | Migrations: 0x4275e9a28b2e9a38e09f6ad34462840e1fdbc618
26 | Saving artifacts...
27 | Running migration: 2_DEV_migrate_dependencies.js
28 | Not in development, so nothing to do. Current network is kovan
29 | Saving artifacts...
30 | Running migration: 3_DEV-deploy_price_feed.js
31 | No need to deploy the Medianizer. Using 0xa944bd4b25c9f186a846fd5668941aa3d3b8425f as the Medianizer address
32 | Deploying PriceOracleInterface with owner: 0xf85d1a0e1b71e72013db51139f285c6d5356b712
33 | Replacing PriceOracleInterface...
34 | [HDWalletProvider] Using nonce: 357
35 | ... 0x997ee57d544c0d1ba45d554a8eadc97e2b93c290464fb3c0d9c3111e01dd921c
36 | PriceOracleInterface: 0xbf72ca4c2e7c0edf1ca82ff6c9f6e9204d1e9580
37 | Saving artifacts...
38 | Running migration: 4_deploy_FRT.js
39 | Running step...
40 | Replacing TokenFRT...
41 | [HDWalletProvider] Using nonce: 358
42 | ... 0xbbc458f59a207f07f03d5d67403242f509f3f77b1aa8728e7e9e0f2d167d4bcd
43 | TokenFRT: 0xb4d40b3dba88e53cdbd9361717f5d86899ede1b3
44 | Deploying TokenFRTProxy with ACCOUNT ==> 0xf85d1a0e1b71e72013db51139f285c6d5356b712
45 | Deploying TokenFRTProxy...
46 | [HDWalletProvider] Using nonce: 359
47 | ... 0xc5cdd5f19ff58da080b9b509dbe2caeb3c20045ebe600edecfaa7534b914f1da
48 | TokenFRTProxy: 0x2b3a76ed4edb76e8fcd261fd978e78efb313d5a2
49 | Saving artifacts...
50 | Running migration: 5_deploy_DX.js
51 | Running step...
52 | Replacing DutchExchange...
53 | [HDWalletProvider] Using nonce: 360
54 | ... 0x0a69add3414410147d96bec629774e634fe74a73de0455a96ca7aa960039e5dc
55 | DutchExchange: 0xab4860ccc54f27a1e2c7a8bed64e2980142461b2
56 | Replacing DutchExchangeProxy...
57 | [HDWalletProvider] Using nonce: 361
58 | ... 0x64d16ed028081a741ae0de0e75714878a5d54474a4d263eb0e71a64861deadb9
59 | DutchExchangeProxy: 0x775ea749a82a87f12199019e5166980f305f4c8f
60 | Saving artifacts...
61 | Running migration: 6_setup_DX.js
62 | Running step...
63 | Setup DX with:
64 | Owner: 0xf85d1a0e1b71e72013db51139f285c6d5356b712
65 | OWL address: 0xb6f77a34ff81dd13fa68b5774d74541a61047fe8
66 | FRT address: 0x2b3a76ed4edb76e8fcd261fd978e78efb313d5a2
67 | WETH address: 0xd0a1e359811322d97991e03f863a0c30c2cf029c
68 | Price Oracle address: 0xbf72ca4c2e7c0edf1ca82ff6c9f6e9204d1e9580
69 | Threshold for new token pair: 10000
70 | Threshold for auction to start: 1000
71 | [HDWalletProvider] Using nonce: 362
72 | ... 0x58abbad7a56677f34a010f8ae53473c664294598be9d665f50ce7d7fd30426c8
73 | Deploy DutchExchangeHelper:
74 | Deploying DutchExchangeHelper...
75 | [HDWalletProvider] Using nonce: 363
76 | ... 0xf9dcb3eb85bbb4283b1c9f29cf3634e021d3b20151af5363f9542e74f78001b6
77 | DutchExchangeHelper: 0xa71d54360d4adf8d52460fe068611dd608b0a8ef
78 | Saving artifacts...
79 | Running migration: 7_set_DX_as_FRT_minter.js
80 | Running step...
81 | [HDWalletProvider] Using nonce: 364
82 | ... 0x523d5a266a2eab273a6ef517e4c39b7c183b9254dac68762a5223823d5e4bcb9
83 | Saving artifacts...
84 | Done in 116.57s.
85 |
--------------------------------------------------------------------------------
/src/truffle/unlock-mgn.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 |
4 | const assert = require('assert')
5 |
6 | const GAS = 5e5 // 500K
7 | const DEFAULT_GAS_PRICE_GWEI = 5 // 5 GWei
8 |
9 | // Usage example:
10 | // yarn MNEMONIC="secret mnemonic" yarn unlock-mgn --network rinkeby --dry-run
11 | // yarn MNEMONIC="secret mnemonic" yarn unlock-mgn --network rinkeby
12 | var argv = require('yargs')
13 | .usage('Usage: yarn unlock-mgn [--gas-price num] [--network name] [--dry-run]')
14 | .option('gasPrice', {
15 | type: 'integer',
16 | default: process.env.GAS_PRICE_GWEI || DEFAULT_GAS_PRICE_GWEI,
17 | describe: 'Gas price for adding each token pair'
18 | })
19 | .option('network', {
20 | type: 'string',
21 | default: 'development',
22 | describe: 'One of the ethereum networks defined in truffle config'
23 | })
24 | .option('dryRun', {
25 | type: 'boolean',
26 | default: false,
27 | describe: 'Dry run. Do not add the token pair, do just the validations.'
28 | })
29 | .help('h')
30 | .strict()
31 | .argv
32 |
33 | async function setAuctioneer () {
34 | if (!argv._[0]) {
35 | argv.showHelp()
36 | } else {
37 | const { gasPrice, network, dryRun, auctioneer: newAuctioneer } = argv
38 | console.log('\n ************** Unlock MGN **************\n')
39 | console.log(`Data:
40 | Dry run: ${dryRun ? 'Yes' : 'No'}
41 | Network: ${network}
42 | Gas: ${GAS}
43 | Gas Price: ${gasPrice} GWei`)
44 |
45 | // Load the DX info
46 | const { mgn, dx, account } = await loadContractsInfo()
47 | const lockedAmount = await mgn.lockedTokenBalances(account)
48 | console.log(`\
49 | User account: ${account}
50 | DutchX address: ${dx.address}
51 | MGN address: ${mgn.address}
52 |
53 | currently locked MGN: ${lockedAmount.div(1e18)}
54 | `)
55 |
56 | if (!lockedAmount.isZero()) {
57 | if (dryRun) {
58 | // Dry run
59 | console.log('The dry run execution passed all validations')
60 | await mgn.unlockTokens.call({
61 | from: account
62 | })
63 | console.log('Dry run success!')
64 | } else {
65 | // Real add token pair execution
66 | console.log('Changing auctioneer to: ' + newAuctioneer)
67 | const txResult = await mgn.unlockTokens({
68 | from: account,
69 | gas: GAS,
70 | gasPrice: gasPrice * 1e9
71 | })
72 | console.log(`Success! ${lockedAmount.div(1e18)} has been unlocked.
73 | They will be withdrawable in 24h.
74 | Transaction: ${txResult.tx}`)
75 | }
76 | } else {
77 | console.log(`The user doesn't have any locked MGN`)
78 | }
79 |
80 |
81 |
82 | console.log('\n ************** Unlock MGN **************\n')
83 | }
84 | }
85 |
86 | async function loadContractsInfo () {
87 | const DutchExchangeProxy = artifacts.require('DutchExchangeProxy')
88 | const DutchExchange = artifacts.require('DutchExchange')
89 | const TokenFRTProxy = artifacts.require('TokenFRTProxy')
90 | const TokenFRT = artifacts.require('TokenFRT')
91 |
92 | // Get contract examples
93 | const dxProxy = await DutchExchangeProxy.deployed()
94 | const dx = DutchExchange.at(dxProxy.address)
95 | const mgnProxy = await TokenFRTProxy.deployed()
96 | const mgn = TokenFRT.at(mgnProxy.address)
97 |
98 | // get Accounts
99 | const accounts = await new Promise((resolve, reject) => {
100 | web3.eth.getAccounts((error, result) => {
101 | if (error) {
102 | reject(error)
103 | } else {
104 | resolve(result)
105 | }
106 | })
107 | })
108 |
109 | return {
110 | mgn,
111 | dx,
112 | account: accounts[0]
113 | }
114 | }
115 |
116 | module.exports = callback => {
117 | setAuctioneer()
118 | .then(callback)
119 | .catch(callback)
120 | }
121 |
--------------------------------------------------------------------------------
/deploy-rinkeby.txt:
--------------------------------------------------------------------------------
1 | yarn run v1.12.3
2 | $ npx truffle migrate --network rinkeby --reset
3 | Create HDWalletProvider
4 | Using gas limit: 6721.975 K
5 | Using gas price: 5 Gwei
6 | Optimizer enabled: true
7 | Sign transactions using: Private Key
8 | Using private key
9 | Truffle 4
10 | Compiling ./contracts/ForTestingOnly/BadToken.sol...
11 | Compiling ./contracts/ForTestingOnly/SubStandardToken.sol...
12 | Compiling ./contracts/ForTestingOnly/TokenGNO.sol...
13 | Compiling @gnosis.pm/util-contracts/contracts/GnosisStandardToken.sol...
14 | Compiling @gnosis.pm/util-contracts/contracts/Math.sol...
15 | Compiling @gnosis.pm/util-contracts/contracts/Proxy.sol...
16 | Compiling @gnosis.pm/util-contracts/contracts/Token.sol...
17 | Writing artifacts to ./build/contracts
18 |
19 | Using network 'rinkeby'.
20 |
21 | Running migration: 1_initial_migration.js
22 | Deploying Migrations...
23 | [HDWalletProvider] Using nonce: 3307
24 | ... 0x431f79e8e8c590554c6e440504df963b3d225507844f92f106afdca314414bf5
25 | Migrations: 0x22fd67707762be0109e64b708c7774900241e40e
26 | Saving artifacts...
27 | Running migration: 2_DEV_migrate_dependencies.js
28 | Not in development, so nothing to do. Current network is rinkeby
29 | Saving artifacts...
30 | Running migration: 3_DEV-deploy_price_feed.js
31 | No need to deploy the Medianizer. Using 0xd6fe8f66520a245626cb4035501903e44fd1ad44 as the Medianizer address
32 | Deploying PriceOracleInterface with owner: 0xf85d1a0e1b71e72013db51139f285c6d5356b712
33 | Replacing PriceOracleInterface...
34 | [HDWalletProvider] Using nonce: 3308
35 | ... 0x6bbf16fb6c46c05d0c7e1c919f797c6e3da995cc07fd9558c2df3eb76f460b99
36 | PriceOracleInterface: 0xbee04d92b297d79889b3bca0c33ed76e02de62b4
37 | Saving artifacts...
38 | Running migration: 4_deploy_FRT.js
39 | Running step...
40 | Replacing TokenFRT...
41 | [HDWalletProvider] Using nonce: 3309
42 | ... 0x35adc72bfb2495307027f2acb6ece4243b119589bf58e6a5a1265579b08198cb
43 | TokenFRT: 0x84fb65d27ffa1c5ed2671e680438a988f295a4f4
44 | Deploying TokenFRTProxy with ACCOUNT ==> 0xf85d1a0e1b71e72013db51139f285c6d5356b712
45 | Replacing TokenFRTProxy...
46 | [HDWalletProvider] Using nonce: 3310
47 | ... 0x85d818256c3d65ba8be5297702cc03b965b9bfdecab84ddfeb569a40e44fcadb
48 | TokenFRTProxy: 0x4ed5e1ec6bdbecf5967fe257f60e05237db9d583
49 | Saving artifacts...
50 | Running migration: 5_deploy_DX.js
51 | Running step...
52 | Replacing DutchExchange...
53 | [HDWalletProvider] Using nonce: 3311
54 | ... 0xbbd3b20e3b310233f76998e95e2ba79c8ba6794ce3228d9910ce351b30f6baa6
55 | DutchExchange: 0x7b7dc59adbe59ca4d0eb32042fd5259cf5329de1
56 | Replacing DutchExchangeProxy...
57 | [HDWalletProvider] Using nonce: 3312
58 | ... 0xfaef0f2ded54fd853f7c90d4e6a15da03d011fad1ecac5f37c3ad63165f9d308
59 | DutchExchangeProxy: 0xaaeb2035ff394fdb2c879190f95e7676f1a9444b
60 | Saving artifacts...
61 | Running migration: 6_setup_DX.js
62 | Running step...
63 | Setup DX with:
64 | Owner: 0xf85d1a0e1b71e72013db51139f285c6d5356b712
65 | OWL address: 0xa7d1c04faf998f9161fc9f800a99a809b84cfc9d
66 | FRT address: 0x4ed5e1ec6bdbecf5967fe257f60e05237db9d583
67 | WETH address: 0xc778417e063141139fce010982780140aa0cd5ab
68 | Price Oracle address: 0xbee04d92b297d79889b3bca0c33ed76e02de62b4
69 | Threshold for new token pair: 10000
70 | Threshold for auction to start: 1000
71 | [HDWalletProvider] Using nonce: 3313
72 | ... 0xa455a25114934c002056d121624028daf842c45cd1987488e121b3a6759af9a1
73 | Deploy DutchExchangeHelper:
74 | Replacing DutchExchangeHelper...
75 | [HDWalletProvider] Using nonce: 3314
76 | ... 0xe8f089304327bc6685fb768c2c9b95c1d914aaa4c98ce77b5612e7ecc5137ddd
77 | DutchExchangeHelper: 0x97f73cde38699065ba00fb5eeb34c02dcda667cd
78 | Saving artifacts...
79 | Running migration: 7_set_DX_as_FRT_minter.js
80 | Running step...
81 | [HDWalletProvider] Using nonce: 3315
82 | ... 0x725bba133d3123378e5ce16a4b1ea9ae3b7aaf44a80708791fec76541001c2ed
83 | Saving artifacts...
84 | Done in 152.13s.
85 |
--------------------------------------------------------------------------------
/test/trufflescripts/deposit_and_sell.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | const {
3 | deployed,
4 | getTokenDeposits,
5 | getAccountsStatsForTokenPairAuction,
6 | getExchangeStatsForTokenPair,
7 | approveForDX,
8 | depositAndSell,
9 | } = require('./utils/contracts')(artifacts)
10 | const { getTime } = require('./utils')(web3)
11 | const argv = require('minimist')(process.argv.slice(2), { string: 'a' })
12 |
13 | /**
14 | * truffle exec test/trufflescripts/deposit_and_sell.js
15 | * to deposit and post a sell order to token pair auction as the seller
16 | * it always posts to the current (if not started) or next auction
17 | * @flags:
18 | * -n for a specific amount of sellToken
19 | * --pair token pair auction, eth,gno by default
20 | * --buyer as the buyer
21 | * -a as the given account
22 | */
23 |
24 |
25 | module.exports = async () => {
26 | const { eth, gno } = await deployed
27 | const availableTokens = { eth, gno }
28 |
29 | const [sell, buy] = argv.pair ? argv.pair.split(',') : ['eth', 'gno']
30 | let sellToken = availableTokens[sell.toLowerCase()] || eth
31 | let buyToken = availableTokens[buy.toLowerCase()] || gno
32 |
33 | if (!sellToken || !buyToken) {
34 | console.warn(`Token ${!sellToken || !buyToken} is not available`)
35 | return
36 | }
37 |
38 | if (argv.n === undefined) {
39 | console.warn('No amount provided')
40 | return
41 | }
42 |
43 | sellToken = sellToken.address
44 | buyToken = buyToken.address
45 |
46 | const sellTokenName = sell ? sell.toUpperCase() : 'ETH'
47 | const buyTokenName = buy ? buy.toUpperCase() : 'GNO'
48 |
49 | let account
50 | if (argv.a) account = argv.a
51 | else if (argv.buyer)[, , account] = web3.eth.accounts
52 | else {
53 | [, account] = web3.eth.accounts
54 | }
55 |
56 | let { [sellTokenName]: sellTokenDeposit = 0 } = await getTokenDeposits(account)
57 |
58 | const { latestAuctionIndex, auctionStart } = await getExchangeStatsForTokenPair({ sellToken, buyToken })
59 | const postingToNextAuction = !(auctionStart === 1 || auctionStart > await getTime())
60 |
61 | const index = postingToNextAuction ? latestAuctionIndex + 1 : latestAuctionIndex
62 |
63 | let [{ sellVolumeCurrent, sellVolumeNext }, { [account]: { sellerBalance } }] = await Promise.all([
64 | getExchangeStatsForTokenPair({ sellToken, buyToken }),
65 | getAccountsStatsForTokenPairAuction({ sellToken, buyToken, index, accounts: [account] }),
66 | ])
67 |
68 | console.log(`Auction ${sellTokenName} -> ${buyTokenName} index ${index} (${postingToNextAuction ? 'next' : 'current'})
69 | was:
70 | sellVolumeCurrent:\t${sellVolumeCurrent}
71 | sellVolumeNext:\t${sellVolumeNext}
72 | sellerBalance:\t${sellerBalance} in auction
73 | sellerDeposit:\t${sellTokenDeposit} ${sellTokenName}
74 | `)
75 |
76 | console.log(`
77 | Approving transfer of ${argv.n} ${sellTokenName} to DX
78 | `)
79 |
80 | const apprTX = await approveForDX(account, { [sellTokenName]: argv.n })
81 | if (!apprTX) return
82 |
83 | console.log(`
84 | Posting deposit and sell order for ${argv.n} ${sellTokenName}
85 | `)
86 |
87 | const tx = await depositAndSell(account, { sellToken, buyToken, amount: argv.n })
88 | if (!tx) return
89 |
90 | [
91 | { [sellTokenName]: sellTokenDeposit = 0 },
92 | { sellVolumeCurrent, sellVolumeNext },
93 | { [account]: { sellerBalance } },
94 | ] = await Promise.all([
95 | getTokenDeposits(account),
96 | getExchangeStatsForTokenPair({ sellToken, buyToken }),
97 | getAccountsStatsForTokenPairAuction({ sellToken, buyToken, index, accounts: [account] }),
98 | ])
99 |
100 | console.log(` now:
101 | sellVolumeCurrent:\t${sellVolumeCurrent}
102 | sellVolumeNext:\t${sellVolumeNext}
103 | sellerBalance:\t${sellerBalance} in auction
104 | sellerDeposit:\t${sellTokenDeposit} ${sellTokenName}
105 | `)
106 | }
107 |
--------------------------------------------------------------------------------
/src/truffle/set-auctioneer.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 |
4 | const assert = require('assert')
5 |
6 | const GAS = 5e5 // 500K
7 | const DEFAULT_GAS_PRICE_GWEI = 5 // 5 GWei
8 |
9 | // Usage example:
10 | // yarn set-auctioneer --auctioneer 0x1 --dry-run
11 | // yarn set-auctioneer --auctioneer 0x1
12 | var argv = require('yargs')
13 | .usage('Usage: yarn set-auctioner [--auctioneer newAddress] [--gas-price num] [--network name] [--dry-run]')
14 | .option('auctioneer', {
15 | type: 'string',
16 | describe: 'New auctioneer'
17 | })
18 | .option('gasPrice', {
19 | type: 'integer',
20 | default: process.env.GAS_PRICE_GWEI || DEFAULT_GAS_PRICE_GWEI,
21 | describe: 'Gas price for adding each token pair'
22 | })
23 | .option('network', {
24 | type: 'string',
25 | default: 'development',
26 | describe: 'One of the ethereum networks defined in truffle config'
27 | })
28 | .option('dryRun', {
29 | type: 'boolean',
30 | default: false,
31 | describe: 'Dry run. Do not add the token pair, do just the validations.'
32 | })
33 | .help('h')
34 | .strict()
35 | .argv
36 |
37 | async function setAuctioneer () {
38 | if (!argv._[0]) {
39 | argv.showHelp()
40 | } else {
41 | const { gasPrice, network, dryRun, auctioneer: newAuctioneer } = argv
42 | console.log('\n ************** Set auctioneer **************\n')
43 | console.log(`Data:
44 | Dry run: ${dryRun ? 'Yes' : 'No'}
45 | Network: ${network}
46 | Gas: ${GAS}
47 | Gas Price: ${gasPrice} GWei`)
48 |
49 | // Load the DX info
50 | const { auctioneer, dx, account } = await loadContractsInfo()
51 | console.log(`\
52 | User account: ${account}
53 | DutchX Auctioneer: ${auctioneer}
54 | DutchX address: ${dx.address}
55 |
56 | Set auctioneer to: ${newAuctioneer}
57 | `)
58 | assert(newAuctioneer, 'auctioneer is a required param')
59 |
60 | if (auctioneer !== newAuctioneer) {
61 | assert.equal(account, auctioneer, 'Only the auctioneer can update the auctioneer. Check the account you are using')
62 |
63 | if (dryRun) {
64 | // Dry run
65 | console.log('The dry run execution passed all validations')
66 | await dx.updateAuctioneer.call(newAuctioneer, {
67 | from: account
68 | })
69 | console.log('Dry run success!')
70 | } else {
71 | // Real add token pair execution
72 | console.log('Changing auctioneer to: ' + newAuctioneer)
73 | const addTokenResult = await dx.updateAuctioneer(newAuctioneer, {
74 | from: account,
75 | gas: GAS,
76 | gasPrice: gasPrice * 1e9
77 | })
78 | console.log('Success! The token pair was added. Transaction: ' + addTokenResult.tx)
79 | }
80 | } else {
81 | console.log(`The auctioneer is already ${newAuctioneer}. So, there nothing to do`)
82 | }
83 |
84 |
85 |
86 | console.log('\n ************** Set auctioneer **************\n')
87 | }
88 | }
89 |
90 | async function loadContractsInfo () {
91 | const DutchExchangeProxy = artifacts.require('DutchExchangeProxy')
92 | const DutchExchange = artifacts.require('DutchExchange')
93 |
94 | // Get contract examples
95 | const dxProxy = await DutchExchangeProxy.deployed()
96 | const dx = DutchExchange.at(dxProxy.address)
97 |
98 | // Get some data from dx
99 | const [
100 | auctioneer,
101 | accounts
102 | ] = await Promise.all([
103 | // Get the auctioneer
104 | dx.auctioneer.call(),
105 |
106 | // get Accounts
107 | new Promise((resolve, reject) => {
108 | web3.eth.getAccounts((error, result) => {
109 | if (error) {
110 | reject(error)
111 | } else {
112 | resolve(result)
113 | }
114 | })
115 | })
116 | ])
117 |
118 | return {
119 | auctioneer,
120 | dx,
121 | account: accounts[0]
122 | }
123 | }
124 |
125 | module.exports = callback => {
126 | setAuctioneer()
127 | .then(callback)
128 | .catch(callback)
129 | }
130 |
--------------------------------------------------------------------------------
/src/truffle/wrap-eth.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 |
4 | const assert = require('assert')
5 | const contract = require('truffle-contract')
6 |
7 | const GAS = 5e5 // 500K
8 |
9 | // Usage example:
10 | // PK=PRIVATE_KEY yarn wrap-eth --amount 40 --dry-run
11 | var argv = require('yargs')
12 | .usage('Usage: yarn wrap-eth [--amount wethAmount] [--network name] [--dry-run]')
13 | .option('amount', {
14 | type: 'integer',
15 | describe: 'Amount of ETH to wrap into WETH',
16 | demandOption: true
17 | })
18 | .option('network', {
19 | type: 'string',
20 | default: 'development',
21 | describe: 'One of the ethereum networks defined in truffle config'
22 | })
23 | .option('dryRun', {
24 | type: 'boolean',
25 | default: false,
26 | describe: 'Dry run. Do not add the token pair, do just the validations.'
27 | })
28 | .help('h')
29 | .strict()
30 | .argv
31 |
32 | async function wrapEth () {
33 | if (!argv._[0]) {
34 | argv.showHelp()
35 | } else {
36 | const { network, amount, dryRun } = argv
37 | console.log('\n ************** Wrap ETH **************\n')
38 | console.log(`Data:
39 | Dry run: ${dryRun ? 'Yes' : 'No'}
40 | Network: ${network}
41 | Gas: ${GAS}
42 | `)
43 |
44 | // Load the DX info
45 | const { weth, dx, account, etherBalance } = await loadContractsInfo()
46 | const wethBalance = await weth.balanceOf(account)
47 | const wethBalanceInDx = await dx.balances(weth.address, account)
48 |
49 | console.log(`\
50 | Addresses:
51 | DutchX address: ${dx.address}
52 | WETH address: ${weth.address}
53 | Account: ${account}
54 | Balances:
55 | Balance of Ether: ${etherBalance / 1e18}
56 | Balance of WETH: ${wethBalance / 1e18}
57 | Balance of WETH in DutchX: ${wethBalanceInDx / 1e18}
58 | Amount to wrap: ${amount}
59 | `)
60 | assert(amount > 0, 'amount must be grater than 0')
61 | assert(amount * 1e18 <= etherBalance, "You don't have enough Ether balance")
62 |
63 | if (dryRun) {
64 | // Dry run
65 | console.log('The dry run execution passed all validations')
66 | await weth.deposit.call({
67 | from: account,
68 | value: amount * 1e18
69 | })
70 | console.log('Dry run success!')
71 | } else {
72 | // Real wrap WETH
73 | console.log('Wrapping %s ETH into WETH', amount)
74 | const wrapResult = await weth.deposit({
75 | from: account,
76 | value: amount * 1e18
77 | })
78 | console.log('Success! Wrapped %s. Transaction: %s', amount, wrapResult.tx)
79 | }
80 |
81 | console.log('\n ************** Wrap ETH **************\n')
82 | }
83 | }
84 |
85 | async function loadContractsInfo () {
86 | const DutchExchangeProxy = artifacts.require('DutchExchangeProxy')
87 | const DutchExchange = artifacts.require('DutchExchange')
88 |
89 | const EtherToken = contract(require('@gnosis.pm/util-contracts/build/contracts/EtherToken'))
90 | EtherToken.setProvider(web3.currentProvider)
91 |
92 | // Get contract examples
93 | const dxProxy = await DutchExchangeProxy.deployed()
94 | const dx = DutchExchange.at(dxProxy.address)
95 | const weth = await EtherToken.deployed()
96 |
97 | // get Accounts
98 | const accounts = await new Promise((resolve, reject) => {
99 | web3.eth.getAccounts((error, result) => {
100 | if (error) {
101 | reject(error)
102 | } else {
103 | resolve(result)
104 | }
105 | })
106 | })
107 |
108 | const account = accounts[0]
109 | const etherBalance = await new Promise((resolve, reject) => {
110 | web3.eth.getBalance(account, (error, result) => {
111 | if (error) {
112 | reject(error)
113 | } else {
114 | resolve(result)
115 | }
116 | })
117 | })
118 |
119 | return {
120 | weth,
121 | dx,
122 | etherBalance,
123 | account
124 | }
125 | }
126 |
127 | module.exports = callback => {
128 | wrapEth()
129 | .then(callback)
130 | .catch(callback)
131 | }
132 |
--------------------------------------------------------------------------------
/src/truffle/set-weth-allowance.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 |
4 | const assert = require('assert')
5 | const contract = require('truffle-contract')
6 |
7 | const GAS = 5e5 // 500K
8 |
9 | // Usage example:
10 | // PK=PRIVATE_KEY yarn set-weth-allowance --amount 40 --dry-run
11 | var argv = require('yargs')
12 | .usage('Usage: yarn set-weth-allowance [--amount wethAmount] [--network name] [--dry-run]')
13 | .option('amount', {
14 | type: 'integer',
15 | describe: 'Amount of WETH to set as the new allowance',
16 | demandOption: true
17 | })
18 | .option('network', {
19 | type: 'string',
20 | default: 'development',
21 | describe: 'One of the ethereum networks defined in truffle config'
22 | })
23 | .option('dryRun', {
24 | type: 'boolean',
25 | default: false,
26 | describe: 'Dry run. Do not add the token pair, do just the validations.'
27 | })
28 | .help('h')
29 | .strict()
30 | .argv
31 |
32 | async function setWethAllowance () {
33 | if (!argv._[0]) {
34 | argv.showHelp()
35 | } else {
36 | const { network, amount, dryRun } = argv
37 | console.log('\n ************** Set WETH Allowance **************\n')
38 | console.log(`Data:
39 | Dry run: ${dryRun ? 'Yes' : 'No'}
40 | Network: ${network}
41 | Gas: ${GAS}
42 | `)
43 |
44 | // Load the DX info
45 | const { weth, dx, account, etherBalance } = await loadContractsInfo()
46 | const wethBalance = await weth.balanceOf(account)
47 | const oldAllowance = await weth.allowance(account, dx.address)
48 | const wethBalanceInDx = await dx.balances(weth.address, account)
49 |
50 | console.log(`\
51 | Addresses:
52 | DutchX address: ${dx.address}
53 | WETH address: ${weth.address}
54 | Account: ${account}
55 | Balances:
56 | Balance of Ether: ${etherBalance / 1e18}
57 | Balance of WETH: ${wethBalance / 1e18}
58 | Balance of WETH in DutchX: ${wethBalanceInDx / 1e18}
59 | Old Allowance: ${oldAllowance / 1e18}
60 | New Allowance: ${amount}
61 | `)
62 |
63 | if (dryRun) {
64 | // Dry run
65 | console.log('The dry run execution passed all validations')
66 | await weth.approve.call(dx.address, amount * 1e18, {
67 | from: account
68 | })
69 | console.log('Dry run success!')
70 | } else {
71 | // Real wrap WETH
72 | console.log('Setting the allowance to %s for WETH', amount)
73 | const setAllowanceResult = await weth.approve(dx.address, amount * 1e18, {
74 | from: account
75 | })
76 | console.log('Success! The allowance is now %s. Transaction: %s', amount, setAllowanceResult.tx)
77 | }
78 |
79 | console.log('\n ************** Set WETH Allowance **************\n')
80 | }
81 | }
82 |
83 | async function loadContractsInfo () {
84 | const DutchExchangeProxy = artifacts.require('DutchExchangeProxy')
85 | const DutchExchange = artifacts.require('DutchExchange')
86 |
87 | const EtherToken = contract(require('@gnosis.pm/util-contracts/build/contracts/EtherToken'))
88 | EtherToken.setProvider(web3.currentProvider)
89 |
90 | // Get contract examples
91 | const dxProxy = await DutchExchangeProxy.deployed()
92 | const dx = DutchExchange.at(dxProxy.address)
93 | const weth = await EtherToken.deployed()
94 |
95 | // get Accounts
96 | const accounts = await new Promise((resolve, reject) => {
97 | web3.eth.getAccounts((error, result) => {
98 | if (error) {
99 | reject(error)
100 | } else {
101 | resolve(result)
102 | }
103 | })
104 | })
105 |
106 | const account = accounts[0]
107 | const etherBalance = await new Promise((resolve, reject) => {
108 | web3.eth.getBalance(account, (error, result) => {
109 | if (error) {
110 | reject(error)
111 | } else {
112 | resolve(result)
113 | }
114 | })
115 | })
116 |
117 | return {
118 | weth,
119 | dx,
120 | etherBalance,
121 | account
122 | }
123 | }
124 |
125 | module.exports = callback => {
126 | setWethAllowance()
127 | .then(callback)
128 | .catch(callback)
129 | }
130 |
--------------------------------------------------------------------------------
/test/trufflescripts/add_token_pair.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0, no-multi-spaces:0, prefer-destructuring:1 */
2 |
3 | const TokenETH = artifacts.require('EtherToken')
4 | const TokenGNO = artifacts.require('TokenGNO')
5 | const PriceOracle = artifacts.require('PriceFeed')
6 | const Medianizer = artifacts.require('Medianizer')
7 | const DutchExchange = artifacts.require('DutchExchange')
8 | const Proxy = artifacts.require('DutchExchangeProxy')
9 |
10 | const argv = require('minimist')(process.argv.slice(2), { string: 'a' })
11 |
12 | /**
13 | * truffle exec test/trufflescripts/add_token_pair.js
14 | * adds a new TokenPair as master account by default
15 | * @flags:
16 | * --seller as the seller
17 | * --buyer as the buyer
18 | * -a as the given address
19 | * --t1 starting T1(ETH) tokens
20 | * --t2 starting T2(GNO) tokens
21 | * --pair token pair auction, eth,gno by default
22 | */
23 |
24 | module.exports = async () => {
25 | const { accounts } = web3.eth
26 | const [master, seller, buyer] = accounts
27 |
28 | let account, accountName
29 | if (argv.a) account = accountName = argv.a
30 | else if (argv.seller) {
31 | account = seller
32 | accountName = 'Seller'
33 | } else if (argv.buyer) {
34 | account = buyer
35 | accountName = 'Buyer'
36 | } else {
37 | account = master
38 | accountName = 'Master'
39 | }
40 |
41 | const dx = await DutchExchange.at(Proxy.address)
42 | const eth = await TokenETH.deployed()
43 | const gno = await TokenGNO.deployed()
44 | const rdn = await TokenGNO.new(web3.toWei(10000, 'ether'), { from: master })
45 | const omg = await TokenGNO.new(web3.toWei(10000, 'ether'), { from: master })
46 | const oracle = await PriceOracle.deployed()
47 | const medianizer = await Medianizer.deployed()
48 |
49 | const availableTokens = {
50 | eth,
51 | gno,
52 | rdn,
53 | omg,
54 | }
55 |
56 | const [sell, buy] = argv.pair ? argv.pair.split(',') : ['eth', 'gno']
57 |
58 | const sellToken = availableTokens[sell.toLowerCase()]
59 | const buyToken = availableTokens[buy.toLowerCase()]
60 |
61 | const startingETH = argv.t1 || web3.toWei(10, 'ether')
62 | const startingGNO = argv.t2 || web3.toWei(10, 'ether')
63 | const ethUSDPrice = web3.toWei(5000, 'ether')
64 |
65 | await Promise.all(accounts.map((acct) => {
66 | const otherToken = sell === 'eth' ? buyToken : sellToken
67 | return Promise.all([
68 | eth.deposit({ from: acct, value: startingETH }),
69 | eth.approve(dx.address, startingETH, { from: acct }),
70 | otherToken.transfer(acct, startingGNO, { from: master }),
71 | otherToken.approve(dx.address, startingGNO, { from: acct }),
72 | ])
73 | }))
74 | // Deposit depends on ABOVE finishing first... so run here
75 | await Promise.all(accounts.map(acct => Promise.all([
76 | dx.deposit(sellToken.address, startingETH, { from: acct }),
77 | dx.deposit(buyToken.address, startingGNO, { from: acct }),
78 | ])))
79 |
80 | await oracle.post(ethUSDPrice, 1516168838 * 2, medianizer.address, { from: master })
81 |
82 | console.log('Threshold new token pair == ', (await dx.thresholdNewTokenPair.call()).toNumber() / (10 ** 18))
83 |
84 | console.log('Account', accountName)
85 | console.log('Sell Token = ', sell, '|| BAL == ', (await dx.balances.call(sellToken.address, account)).toNumber() / (10 ** 18))
86 | console.log('Buy Token = ', buy, '|| BAL == ', (await dx.balances.call(buyToken.address, account)).toNumber() / (10 ** 18))
87 |
88 | console.log('FundingUSD == ', startingETH * ethUSDPrice)
89 | console.log('Auction Index == ', (await dx.getAuctionIndex.call(sellToken.address, buyToken.address)).toNumber())
90 |
91 | const funds = sell === 'eth' ?
92 | [web3.toWei(10, 'ether'), 0, 2, 1] :
93 | [0, web3.toWei(10, 'ether'), 1, 2]
94 |
95 | return dx.addTokenPair(
96 | sellToken.address, // -----> SellToken Address
97 | buyToken.address, // -----> BuyToken Address
98 | ...funds, // -----> sellFund, buyFund, closingPriceNum, closingPriceDen
99 | { from: account },
100 | )
101 | }
102 |
--------------------------------------------------------------------------------
/test/trufflescripts/increase_time.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:0 */
2 | const { deployed, getExchangeStatsForTokenPair, getAuctionStatsForTokenPair } = require('./utils/contracts')(artifacts)
3 | const { getTime, increaseTimeBy, setTime } = require('./utils')(web3)
4 |
5 | const argv = require('minimist')(process.argv.slice(2))
6 |
7 | const getTimeStr = (timestamp) => {
8 | const date = new Date(Math.abs(timestamp))
9 | const hh = date.getUTCHours()
10 | const mm = date.getUTCMinutes()
11 | const ss = date.getUTCSeconds()
12 |
13 | return `${hh ? `${hh} hour(s) ` : ''}${mm ? `${mm} minute(s) ` : ''}${ss ? `${ss} second(s) ` : ''}`
14 | }
15 |
16 | const getSeconds = ({ h = 0, m = 0, s = 0 }) => (h * 60 * 60) + (m * 60) + s
17 |
18 | const getNumDenStr = ([num, den]) => `${num}/${den} = ${(num / den).toFixed(8)}`
19 |
20 | /**
21 | * truffle exec test/trufflescripts/increase_timer.js
22 | * increases auction time
23 | * @flags:
24 | * --start first, sets time to auction start
25 | * --clear or auction end,
26 | * then increases time by
27 | * -h given hours
28 | * -m given minutes
29 | * -s given seconds
30 | */
31 |
32 | module.exports = async () => {
33 | const { eth, gno } = await deployed
34 |
35 | const printAuctionTimes = async () => {
36 | const now = getTime()
37 | const {
38 | auctionStart,
39 | latestAuctionIndex,
40 | sellTokenOraclePrice,
41 | buyTokenOraclePrice,
42 | } = await getExchangeStatsForTokenPair({ sellToken: eth, buyToken: gno })
43 |
44 | // const timeUntilStart = auctionStart - now
45 | // const timeStr = getTimeStr(timeUntilStart * 1000)
46 |
47 |
48 | console.log(`
49 | Auction index ${latestAuctionIndex}
50 | ______________________________________
51 | now:\t\t\t${new Date(now * 1000).toTimeString()}
52 | auctionStart:\t\t\t${new Date(auctionStart * 1000).toTimeString()}
53 | `)
54 |
55 | if (auctionStart === 0) {
56 | console.log('auction has never run before')
57 | } else {
58 | const timeUntilStart = auctionStart - now
59 | const timeStr = getTimeStr(timeUntilStart * 1000)
60 |
61 | if (timeUntilStart > 0) {
62 | console.log(`next auction starts in\t\t${timeStr}`)
63 | } else if (timeUntilStart < 0) {
64 | console.log(`auction started\t\t${timeStr}ago`)
65 | } else {
66 | console.log('auction just started')
67 | }
68 | }
69 |
70 | const {
71 | price,
72 | sellVolume,
73 | buyVolume,
74 | } = await getAuctionStatsForTokenPair({ sellToken: eth, buyToken: gno, index: latestAuctionIndex })
75 |
76 | let timeWhenAuctionClears
77 |
78 | if (price && sellTokenOraclePrice && buyTokenOraclePrice) {
79 | const [num, den] = price
80 |
81 | const amountToClearAuction = Math.floor((sellVolume * num) / den) - buyVolume
82 | console.log(`\n currentPrice: 1 ETH = ${getNumDenStr(price)} GNO`)
83 |
84 | if (amountToClearAuction > 0) console.log(` to clear auction buy\t${amountToClearAuction} GNO`)
85 |
86 | timeWhenAuctionClears = 86400 + auctionStart
87 |
88 | if (auctionStart === 1 || auctionStart > now) {
89 | console.log(' auction haven\t started yet')
90 | } else if (now < timeWhenAuctionClears) {
91 | const timeUntilAuctionClears = getTimeStr((now - timeWhenAuctionClears) * 1000)
92 | console.log(` will clear with time in ${timeUntilAuctionClears}`)
93 | }
94 | }
95 |
96 | return { auctionStart, timeWhenAuctionClears }
97 | }
98 |
99 | const { auctionStart, timeWhenAuctionClears } = await printAuctionTimes()
100 |
101 | const incTimeBy = getSeconds(argv)
102 |
103 | console.log(`Setting time to ${argv.start ? 'AUCTION_START' : argv.clear ? 'AUCTION_END' : ''} ${incTimeBy ? `+ ${getTimeStr(incTimeBy * 1000)}` : ''}`)
104 |
105 | if (argv.start) {
106 | setTime(auctionStart, incTimeBy)
107 | } else if (argv.clear && timeWhenAuctionClears !== undefined && timeWhenAuctionClears !== Infinity) {
108 | setTime(timeWhenAuctionClears, incTimeBy)
109 | }
110 |
111 | if (incTimeBy) {
112 | increaseTimeBy(incTimeBy)
113 | }
114 |
115 | console.log('==========================')
116 |
117 | await printAuctionTimes()
118 | }
119 |
--------------------------------------------------------------------------------
/src/truffle/deposit-weth.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 |
4 | const assert = require('assert')
5 | const contract = require('truffle-contract')
6 |
7 | const GAS = 5e5 // 500K
8 |
9 | // Usage example:
10 | // PK=PRIVATE_KEY yarn deposit-weth --amount 40 --dry-run
11 | var argv = require('yargs')
12 | .usage('Usage: yarn deposit-weth [--amount wethAmount] [--network name] [--dry-run]')
13 | .option('amount', {
14 | type: 'integer',
15 | describe: 'Amount of WETH to set as the new allowance',
16 | demandOption: true
17 | })
18 | .option('network', {
19 | type: 'string',
20 | default: 'development',
21 | describe: 'One of the ethereum networks defined in truffle config'
22 | })
23 | .option('dryRun', {
24 | type: 'boolean',
25 | default: false,
26 | describe: 'Dry run. Do not add the token pair, do just the validations.'
27 | })
28 | .help('h')
29 | .strict()
30 | .argv
31 |
32 | async function depositWeth () {
33 | if (!argv._[0]) {
34 | argv.showHelp()
35 | } else {
36 | const { network, amount, dryRun } = argv
37 | console.log('\n ************** Deposit WETH **************\n')
38 | console.log(`Data:
39 | Dry run: ${dryRun ? 'Yes' : 'No'}
40 | Network: ${network}
41 | Gas: ${GAS}
42 | `)
43 |
44 | // Load the DX info
45 | const { weth, dx, account, etherBalance } = await loadContractsInfo()
46 | const wethBalance = await weth.balanceOf(account)
47 | const allowance = await weth.allowance(account, dx.address)
48 | const wethBalanceInDx = await dx.balances(weth.address, account)
49 |
50 | console.log(`\
51 | Addresses:
52 | DutchX address: ${dx.address}
53 | WETH address: ${weth.address}
54 | Account: ${account}
55 | Balances:
56 | Balance of Ether: ${etherBalance / 1e18}
57 | Balance of WETH: ${wethBalance / 1e18}
58 | Balance of WETH in DutchX: ${wethBalanceInDx / 1e18}
59 | WETH allowance for DutchX: ${allowance / 1e18}
60 | Amount: ${amount}
61 | `)
62 |
63 | assert(amount > 0, 'amount must be grater than 0')
64 | assert(amount * 1e18 <= wethBalance, "You don't have enough WETH")
65 | assert(amount * 1e18 <= allowance, "You don't have allowance")
66 |
67 | if (dryRun) {
68 | // Dry run
69 | console.log('The dry run execution passed all validations')
70 | await dx.deposit.call(weth.address, amount * 1e18, {
71 | from: account
72 | })
73 | console.log('Dry run success!')
74 | } else {
75 | // Real wrap WETH
76 | console.log('Setting the allowance to %s for WETH', amount)
77 | const setAllowanceResult = await dx.deposit(weth.address, amount * 1e18, {
78 | from: account
79 | })
80 | console.log('Success! The allowance is now %s. Transaction: %s', amount, setAllowanceResult.tx)
81 | }
82 |
83 | console.log('\n ************** Deposit WETH **************\n')
84 | }
85 | }
86 |
87 | async function loadContractsInfo () {
88 | const DutchExchangeProxy = artifacts.require('DutchExchangeProxy')
89 | const DutchExchange = artifacts.require('DutchExchange')
90 |
91 | const EtherToken = contract(require('@gnosis.pm/util-contracts/build/contracts/EtherToken'))
92 | EtherToken.setProvider(web3.currentProvider)
93 |
94 | // Get contract examples
95 | const dxProxy = await DutchExchangeProxy.deployed()
96 | const dx = DutchExchange.at(dxProxy.address)
97 | const weth = await EtherToken.deployed()
98 |
99 | // get Accounts
100 | const accounts = await new Promise((resolve, reject) => {
101 | web3.eth.getAccounts((error, result) => {
102 | if (error) {
103 | reject(error)
104 | } else {
105 | resolve(result)
106 | }
107 | })
108 | })
109 |
110 | const account = accounts[0]
111 | const etherBalance = await new Promise((resolve, reject) => {
112 | web3.eth.getBalance(account, (error, result) => {
113 | if (error) {
114 | reject(error)
115 | } else {
116 | resolve(result)
117 | }
118 | })
119 | })
120 |
121 | return {
122 | weth,
123 | dx,
124 | etherBalance,
125 | account
126 | }
127 | }
128 |
129 | module.exports = callback => {
130 | depositWeth()
131 | .then(callback)
132 | .catch(callback)
133 | }
134 |
--------------------------------------------------------------------------------
/src/truffle/claim-unlocked-mgn.js:
--------------------------------------------------------------------------------
1 | /* global artifacts, web3 */
2 | /* eslint no-undef: "error" */
3 |
4 | const assert = require('assert')
5 |
6 | const GAS = 5e5 // 500K
7 | const DEFAULT_GAS_PRICE_GWEI = 5 // 5 GWei
8 |
9 | // Usage example:
10 | // yarn MNEMONIC="secret mnemonic" yarn claim-unlocked-mgn --network rinkeby --dry-run
11 | // yarn MNEMONIC="secret mnemonic" yarn claim-unlocked-mgn --network rinkeby
12 | var argv = require('yargs')
13 | .usage('Usage: yarn claim-unlocked-mgn [--gas-price num] [--network name] [--dry-run]')
14 | .option('gasPrice', {
15 | type: 'integer',
16 | default: process.env.GAS_PRICE_GWEI || DEFAULT_GAS_PRICE_GWEI,
17 | describe: 'Gas price for adding each token pair'
18 | })
19 | .option('network', {
20 | type: 'string',
21 | default: 'development',
22 | describe: 'One of the ethereum networks defined in truffle config'
23 | })
24 | .option('dryRun', {
25 | type: 'boolean',
26 | default: false,
27 | describe: 'Dry run. Do not add the token pair, do just the validations.'
28 | })
29 | .help('h')
30 | .strict()
31 | .argv
32 |
33 | async function setAuctioneer () {
34 | if (!argv._[0]) {
35 | argv.showHelp()
36 | } else {
37 | const { gasPrice, network, dryRun, auctioneer: newAuctioneer } = argv
38 | console.log('\n ************** Claim unlocked MGN **************\n')
39 | console.log(`Data:
40 | Dry run: ${dryRun ? 'Yes' : 'No'}
41 | Network: ${network}
42 | Gas: ${GAS}
43 | Gas Price: ${gasPrice} GWei`)
44 |
45 | // Load the DX info
46 | const { mgn, dx, account } = await loadContractsInfo()
47 | const [ amountUnlocked, withdrawalTimeSeconds ] = await mgn.unlockedTokens(account)
48 | const withdrawalTime = new Date(withdrawalTimeSeconds.toNumber() * 1000)
49 | const withdrawalTimeFmt = withdrawalTime.toLocaleDateString() + ' ' +
50 | withdrawalTime.getHours() + ':' + withdrawalTime.getMinutes()
51 |
52 | console.log(`\
53 | User account: ${account}
54 | DutchX address: ${dx.address}
55 | MGN address: ${mgn.address}
56 |
57 | Currently unlocked MGN: ${amountUnlocked.div(1e18)}
58 | Withdraw time for unlocked MGN: ${withdrawalTimeFmt}
59 | `)
60 |
61 | const now = new Date()
62 | if (amountUnlocked.isZero()) {
63 | console.log(`The user doesn't have any unlocked MGN`)
64 | } else if (withdrawalTime > now) {
65 | console.log(`The user has unlockded MGN, but is not claimable yet`)
66 | } else {
67 | // Ready to claim
68 | if (dryRun) {
69 | // Dry run
70 | console.log('The dry run execution passed all validations')
71 | await mgn.withdrawUnlockedTokens.call({
72 | from: account
73 | })
74 | console.log('Dry run success!')
75 | } else {
76 | // Real add token pair execution
77 | console.log('Changing auctioneer to: ' + newAuctioneer)
78 | const txResult = await mgn.withdrawUnlockedTokens({
79 | from: account,
80 | gas: GAS,
81 | gasPrice: gasPrice * 1e9
82 | })
83 | console.log(`Success! ${amountUnlocked.div(1e18)} has been unlocked. Transaction: ${txResult.tx}`)
84 | }
85 | }
86 | console.log('\n ************** Claim unlocked MGN **************\n')
87 | }
88 | }
89 |
90 | async function loadContractsInfo () {
91 | const DutchExchangeProxy = artifacts.require('DutchExchangeProxy')
92 | const DutchExchange = artifacts.require('DutchExchange')
93 | const TokenFRTProxy = artifacts.require('TokenFRTProxy')
94 | const TokenFRT = artifacts.require('TokenFRT')
95 |
96 | // Get contract examples
97 | const dxProxy = await DutchExchangeProxy.deployed()
98 | const dx = DutchExchange.at(dxProxy.address)
99 | const mgnProxy = await TokenFRTProxy.deployed()
100 | const mgn = TokenFRT.at(mgnProxy.address)
101 |
102 | // get Accounts
103 | const accounts = await new Promise((resolve, reject) => {
104 | web3.eth.getAccounts((error, result) => {
105 | if (error) {
106 | reject(error)
107 | } else {
108 | resolve(result)
109 | }
110 | })
111 | })
112 |
113 | return {
114 | mgn,
115 | dx,
116 | account: accounts[0]
117 | }
118 | }
119 |
120 | module.exports = callback => {
121 | setAuctioneer()
122 | .then(callback)
123 | .catch(callback)
124 | }
125 |
--------------------------------------------------------------------------------
/test/dutchExchange-priceOracle.spec.js:
--------------------------------------------------------------------------------
1 | /* global contract, assert, artifacts */
2 | /* eslint no-undef: "error" */
3 |
4 | const {
5 | assertRejects,
6 | gasLogger,
7 | enableContractFlag,
8 | toEth
9 | } = require('./utils')
10 |
11 | const {
12 | getContracts,
13 | setupTest,
14 | wait
15 | } = require('./testFunctions')
16 |
17 | const Medianizer = artifacts.require('Medianizer')
18 | const PriceFeed = artifacts.require('PriceFeed')
19 | const PriceOracleInterface = artifacts.require('PriceOracleInterface')
20 |
21 | // Test VARS
22 | let oracle
23 | let priceFeed
24 | let dx
25 | let medzr2
26 | let contracts
27 | let newPriceOracleInterface
28 |
29 | const setupContracts = async () => {
30 | contracts = await getContracts({ resetCache: true });
31 | // destructure contracts into upper state
32 | ({
33 | PriceOracleInterface: oracle,
34 | PriceFeed: priceFeed,
35 | DutchExchange: dx
36 | } = contracts)
37 | }
38 |
39 | const c1 = () => contract('DX PriceOracleInterface Flow', accounts => {
40 | const [owner, notOwner, newCurator] = accounts
41 | // Accounts to fund for faster setupTest
42 | const setupAccounts = [owner, notOwner, newCurator]
43 |
44 | const startBal = {
45 | startingETH: 1000.0.toWei(),
46 | startingGNO: 1000.0.toWei(),
47 | ethUSDPrice: 1100.0.toWei(), // 400 ETH @ $6000/ETH = $2,400,000 USD
48 | sellingAmount: 100.0.toWei() // Same as web3.toWei(50, 'ether') - $60,000USD
49 | }
50 |
51 | afterEach(gasLogger)
52 |
53 | it('SETUP: fund accounts, fund DX', async () => {
54 | // get contracts
55 | await setupContracts()
56 | contracts.medzr2 = await Medianizer.new()
57 | contracts.priceFeed2 = await PriceFeed.new();
58 | ({ medzr2 } = contracts)
59 |
60 | // set up accounts and tokens[contracts]
61 | await setupTest(setupAccounts, contracts, startBal)
62 | })
63 |
64 | it('raiseEmergency: throws when NON-OWNER tries to call it', async () =>
65 | assertRejects(oracle.raiseEmergency(true, { from: notOwner }))
66 | )
67 |
68 | it('raiseEmergency: switches into emergency mode', async () => {
69 | await oracle.raiseEmergency(true, { from: owner })
70 |
71 | let ethUSDPrice = (await oracle.getUSDETHPrice.call()).toNumber()
72 | assert.equal(ethUSDPrice, 600, 'Oracle ethUSDPrice should report emergency price')
73 | await oracle.raiseEmergency(false, { from: owner })
74 |
75 | ethUSDPrice = (await oracle.getUSDETHPrice.call()).toNumber()
76 | assert.equal(ethUSDPrice, 1100, 'Oracle ethUSDPrice should on longer report emergency price')
77 | })
78 |
79 | it('getUSDETHPrice: calls this correctly', async () => {
80 | const ethUSDPrice = (await oracle.getUSDETHPrice.call()).toNumber()
81 | assert.equal(ethUSDPrice, 1100, 'Oracle ethUSDPrice is not the set price ethUSDPrice: 1100..toWei(),')
82 | })
83 |
84 | it('getUSDETHPrice: price is correctly restricted if actual price is 0', async () => {
85 | newPriceOracleInterface = await PriceOracleInterface.new(owner, medzr2.address)
86 | await dx.initiateEthUsdOracleUpdate(newPriceOracleInterface.address, { from: owner })
87 | await assertRejects(dx.updateEthUSDOracle({ from: owner }))
88 | await wait(60 * 60 * 24 * 30 + 5)
89 | await dx.updateEthUSDOracle({ from: owner })
90 | const ethUSDPrice = (await newPriceOracleInterface.getUSDETHPrice.call()).toNumber()
91 | assert.equal(ethUSDPrice, 1, 'Oracle ethUSDPrice is not set and should return 1')
92 | })
93 | it('getUSDETHPrice: set price should work correctly', async () => {
94 | const ethUSDPrice = 1500.0.toWei()
95 | const medzr = await Medianizer.at(medzr2.address)
96 | await medzr.set(PriceFeed.address, { from: owner })
97 | await priceFeed.post(ethUSDPrice, 1516168838 * 2, medzr2.address, { from: owner })
98 | const getNewETHUSDPrice = await newPriceOracleInterface.getUSDETHPrice.call()
99 |
100 | assert.equal(toEth(ethUSDPrice).toString(), getNewETHUSDPrice.toString(), 'Should be same')
101 | })
102 |
103 | it('updateCurator: throws when NON-OWNER tries to change curator',
104 | async () => assertRejects(oracle.updateCurator(medzr2, { from: notOwner }))
105 | )
106 |
107 | it('updateCurator: switches OWNER to new OWNER', async () => {
108 | const oldOwner = await oracle.owner.call()
109 | await oracle.updateCurator(newCurator, { from: owner })
110 | const newOwner = await oracle.owner.call()
111 |
112 | assert.notEqual(oldOwner, newOwner, 'Old Owner should NOT == New Owner')
113 | assert.equal(newCurator, newOwner, 'New Curator passed in is indeed newOwner')
114 | })
115 | })
116 |
117 | enableContractFlag(c1)
118 |
--------------------------------------------------------------------------------
/test/dutchExchange-getCurrentAuctionPrice.spec.js:
--------------------------------------------------------------------------------
1 | /* global contract, assert */
2 | /* eslint no-undef: "error" */
3 |
4 | const {
5 | BN,
6 | eventWatcher,
7 | log,
8 | timestamp
9 | } = require('./utils')
10 |
11 | const {
12 | setupTest,
13 | getContracts,
14 | getAuctionIndex,
15 | waitUntilPriceIsXPercentOfPreviousPrice,
16 | setAndCheckAuctionStarted,
17 | postBuyOrder
18 | } = require('./testFunctions')
19 |
20 | // Test VARS
21 | let eth
22 | let gno
23 | let dx
24 |
25 | let contracts
26 |
27 | const setupContracts = async () => {
28 | contracts = await getContracts({ resetCache: true });
29 | // destructure contracts into upper state
30 | ({
31 | DutchExchange: dx,
32 | EtherToken: eth,
33 | TokenGNO: gno
34 | } = contracts)
35 | }
36 | const startBal = {
37 | startingETH: 90.0.toWei(),
38 | startingGNO: 90.0.toWei(),
39 | ethUSDPrice: 1008.0.toWei(),
40 | sellingAmount: 50.0.toWei() // Same as web3.toWei(50, 'ether')
41 | }
42 |
43 | contract('DutchExchange - getCurrentAuctionPrice', accounts => {
44 | const [master, seller1, , buyer1, buyer2] = accounts
45 | // Accounts to fund for faster setupTest
46 | const setupAccounts = [master, seller1, buyer1, buyer2]
47 |
48 | before(async () => {
49 | // get contracts
50 | await setupContracts()
51 |
52 | // set up accounts and tokens[contracts]
53 | await setupTest(setupAccounts, contracts, startBal)
54 |
55 | // add tokenPair ETH GNO
56 | await dx.addTokenPair(
57 | eth.address,
58 | gno.address,
59 | 10.0.toWei(),
60 | 0,
61 | 2,
62 | 1,
63 | { from: seller1 }
64 | )
65 |
66 | eventWatcher(dx, 'Log', {})
67 | })
68 |
69 | after(eventWatcher.stopWatching)
70 |
71 | it('1. check that getCurrentAuctionPrice returns the right value according to time for a normal running auction', async () => {
72 | const auctionIndex = await getAuctionIndex()
73 | await setAndCheckAuctionStarted(eth, gno)
74 | const auctionStart = (await dx.getAuctionStart.call(eth.address, gno.address)).toNumber()
75 | await waitUntilPriceIsXPercentOfPreviousPrice(eth, gno, 1.5)
76 |
77 | const { num, den } = await dx.getCurrentAuctionPrice.call(eth.address, gno.address, auctionIndex)
78 | const currenttime = await timestamp()
79 | const { num: numPrevious, den: denPrevious } = await dx.getPriceInPastAuction.call(eth.address, gno.address, auctionIndex - 1)
80 | const timeElapsed = currenttime - auctionStart
81 | log('numPrevious', numPrevious)
82 | log('timeE', timeElapsed)
83 | assert.equal(num.toString(), (new BN((86400 - timeElapsed).toString())).mul(numPrevious).toString())
84 | assert.equal(den.toString(), (new BN((timeElapsed + 43200).toString())).mul(denPrevious).toString())
85 | })
86 |
87 | it('2. check that getCurrentAuctionPrice returns the right value (closing Price ) for a theoretical closed auction', async () => {
88 | const auctionIndex = await getAuctionIndex()
89 |
90 | await postBuyOrder(eth, gno, auctionIndex, 5.0.toWei(), buyer1)
91 | await postBuyOrder(eth, gno, auctionIndex, 5.0.toWei(), buyer2)
92 | // closing theoretical
93 | await waitUntilPriceIsXPercentOfPreviousPrice(eth, gno, 0.4)
94 |
95 | // check prices: - actually reduantant with tests postBuyOrder
96 | const closingPriceNum = await dx.buyVolumes.call(eth.address, gno.address)
97 | const closingPriceDen = await dx.sellVolumesCurrent.call(eth.address, gno.address)
98 | const { num, den } = await dx.getCurrentAuctionPrice.call(eth.address, gno.address, auctionIndex)
99 | assert.equal(closingPriceNum.toString(), num.toString())
100 | assert.equal(closingPriceDen.toString(), den.toString())
101 | })
102 |
103 | it('3. check that getCurrentAuctionPrice returns the (0,0) for future auctions', async () => {
104 | const auctionIndex = await getAuctionIndex()
105 | const { num, den } = await dx.getCurrentAuctionPrice.call(eth.address, gno.address, auctionIndex + 1)
106 | assert.equal(0, num)
107 | assert.equal(0, den)
108 | })
109 |
110 | it('4. check that getCurrentAuctionPrice returns the right value (closing Price ) for a closed auction', async () => {
111 | const auctionIndex = await getAuctionIndex()
112 |
113 | // clearning the auction
114 | await postBuyOrder(eth, gno, auctionIndex, 5.0.toWei(), buyer2)
115 | const { num: closingPriceNum, den: closingPriceDen } = await dx.closingPrices.call(eth.address, gno.address, auctionIndex)
116 | const { num, den } = await dx.getCurrentAuctionPrice.call(eth.address, gno.address, auctionIndex)
117 | assert.equal(closingPriceNum.toString(), num.toString())
118 | assert.equal(closingPriceDen.toString(), den.toString())
119 | })
120 | })
121 |
--------------------------------------------------------------------------------
/contracts/Oracle/DSMath.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 |
4 | contract DSMath {
5 | /*
6 | standard uint256 functions
7 | */
8 |
9 | function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
10 | assert((z = x + y) >= x);
11 | }
12 |
13 | function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
14 | assert((z = x - y) <= x);
15 | }
16 |
17 | function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
18 | assert((z = x * y) >= x);
19 | }
20 |
21 | function div(uint256 x, uint256 y) internal pure returns (uint256 z) {
22 | z = x / y;
23 | }
24 |
25 | function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
26 | return x <= y ? x : y;
27 | }
28 |
29 | function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
30 | return x >= y ? x : y;
31 | }
32 |
33 | /*
34 | uint128 functions (h is for half)
35 | */
36 |
37 | function hadd(uint128 x, uint128 y) internal pure returns (uint128 z) {
38 | assert((z = x + y) >= x);
39 | }
40 |
41 | function hsub(uint128 x, uint128 y) internal pure returns (uint128 z) {
42 | assert((z = x - y) <= x);
43 | }
44 |
45 | function hmul(uint128 x, uint128 y) internal pure returns (uint128 z) {
46 | assert((z = x * y) >= x);
47 | }
48 |
49 | function hdiv(uint128 x, uint128 y) internal pure returns (uint128 z) {
50 | z = x / y;
51 | }
52 |
53 | function hmin(uint128 x, uint128 y) internal pure returns (uint128 z) {
54 | return x <= y ? x : y;
55 | }
56 |
57 | function hmax(uint128 x, uint128 y) internal pure returns (uint128 z) {
58 | return x >= y ? x : y;
59 | }
60 |
61 | /*
62 | int256 functions
63 | */
64 |
65 | function imin(int256 x, int256 y) internal pure returns (int256 z) {
66 | return x <= y ? x : y;
67 | }
68 |
69 | function imax(int256 x, int256 y) internal pure returns (int256 z) {
70 | return x >= y ? x : y;
71 | }
72 |
73 | /*
74 | WAD math
75 | */
76 |
77 | uint128 constant WAD = 10 ** 18;
78 |
79 | function wadd(uint128 x, uint128 y) internal pure returns (uint128) {
80 | return hadd(x, y);
81 | }
82 |
83 | function wsub(uint128 x, uint128 y) internal pure returns (uint128) {
84 | return hsub(x, y);
85 | }
86 |
87 | function wmul(uint128 x, uint128 y) internal pure returns (uint128 z) {
88 | z = cast((uint256(x) * y + WAD / 2) / WAD);
89 | }
90 |
91 | function wdiv(uint128 x, uint128 y) internal pure returns (uint128 z) {
92 | z = cast((uint256(x) * WAD + y / 2) / y);
93 | }
94 |
95 | function wmin(uint128 x, uint128 y) internal pure returns (uint128) {
96 | return hmin(x, y);
97 | }
98 |
99 | function wmax(uint128 x, uint128 y) internal pure returns (uint128) {
100 | return hmax(x, y);
101 | }
102 |
103 | /*
104 | RAY math
105 | */
106 |
107 | uint128 constant RAY = 10 ** 27;
108 |
109 | function radd(uint128 x, uint128 y) internal pure returns (uint128) {
110 | return hadd(x, y);
111 | }
112 |
113 | function rsub(uint128 x, uint128 y) internal pure returns (uint128) {
114 | return hsub(x, y);
115 | }
116 |
117 | function rmul(uint128 x, uint128 y) internal pure returns (uint128 z) {
118 | z = cast((uint256(x) * y + RAY / 2) / RAY);
119 | }
120 |
121 | function rdiv(uint128 x, uint128 y) internal pure returns (uint128 z) {
122 | z = cast((uint256(x) * RAY + y / 2) / y);
123 | }
124 |
125 | function rpow(uint128 x, uint64 n) internal pure returns (uint128 z) {
126 | // This famous algorithm is called "exponentiation by squaring"
127 | // and calculates x^n with x as fixed-point and n as regular unsigned.
128 | //
129 | // It's O(log n), instead of O(n) for naive repeated multiplication.
130 | //
131 | // These facts are why it works:
132 | //
133 | // If n is even, then x^n = (x^2)^(n/2).
134 | // If n is odd, then x^n = x * x^(n-1),
135 | // and applying the equation for even x gives
136 | // x^n = x * (x^2)^((n-1) / 2).
137 | //
138 | // Also, EVM division is flooring and
139 | // floor[(n-1) / 2] = floor[n / 2].
140 |
141 | z = n % 2 != 0 ? x : RAY;
142 |
143 | for (n /= 2; n != 0; n /= 2) {
144 | x = rmul(x, x);
145 |
146 | if (n % 2 != 0) {
147 | z = rmul(z, x);
148 | }
149 | }
150 | }
151 |
152 | function rmin(uint128 x, uint128 y) internal pure returns (uint128) {
153 | return hmin(x, y);
154 | }
155 |
156 | function rmax(uint128 x, uint128 y) internal pure returns (uint128) {
157 | return hmax(x, y);
158 | }
159 |
160 | function cast(uint256 x) internal pure returns (uint128 z) {
161 | assert((z = uint128(x)) == x);
162 | }
163 |
164 | }
165 |
--------------------------------------------------------------------------------
/test/dutchExchange-TokenApproval.spec.js:
--------------------------------------------------------------------------------
1 | /* global contract, assert */
2 | /* eslint no-undef: "error" */
3 |
4 | const {
5 | logger,
6 | assertRejects,
7 | gasLogger
8 | } = require('./utils')
9 |
10 | const { getContracts } = require('./testFunctions')
11 |
12 | // Test VARS
13 | let eth
14 | let gno
15 | let dx
16 |
17 | let contracts
18 |
19 | contract('DutchExchange updating token approval', accounts => {
20 | const [master, seller1] = accounts
21 | let testingTokens
22 |
23 | afterEach(gasLogger)
24 | before(async () => {
25 | // get contracts
26 | contracts = await getContracts({ resetCache: true });
27 | // destructure contracts into upper state
28 | ({
29 | DutchExchange: dx,
30 | EtherToken: eth,
31 | TokenGNO: gno
32 | } = contracts)
33 |
34 | testingTokens = [eth, gno]
35 | })
36 |
37 | const getTokenApproval = token => {
38 | const addr = token.address || token
39 |
40 | return dx.approvedTokens.call(addr)
41 | }
42 |
43 | const getAndPrintApproval = async (token, symbol) => {
44 | const approved = await getTokenApproval(token)
45 | logger(`Token ${symbol} at ${token.address} is ${approved ? '' : 'NOT'} APPROVED`)
46 |
47 | return approved
48 | }
49 |
50 | const assertIsOwner = async acc => {
51 | const owner = await dx.auctioneer.call()
52 | assert.strictEqual(owner, acc, 'account should be DutchExchange contract owner')
53 | }
54 |
55 | const assertIsNotOwner = async acc => {
56 | const owner = await dx.auctioneer.call()
57 | assert.notStrictEqual(owner, acc, 'account should not be DutchExchange contract owner')
58 | }
59 |
60 | it('intially tokens aren\'t approved', () => Promise.all(testingTokens.map(async token => {
61 | const symbol = await token.symbol.call()
62 | const approved = await getAndPrintApproval(token, symbol)
63 |
64 | assert.isFalse(approved, `${symbol} token shouldn't be approved yet`)
65 | })))
66 |
67 | it('not owner can\'t set token approval', () => Promise.all(testingTokens.map(async token => {
68 | const symbol = await token.symbol.call()
69 | const approved1 = await getAndPrintApproval(token, symbol)
70 | assert.isFalse(approved1, `${symbol} token is not approved`)
71 |
72 | await assertIsNotOwner(seller1)
73 |
74 | logger(`Not owner tries to change ${symbol} approval to ${!approved1}`)
75 |
76 | await assertRejects(dx.updateApprovalOfToken([token.address], !approved1, { from: seller1 }), `not owner can't set ${symbol} token approval`)
77 |
78 | const approved2 = await getAndPrintApproval(token, symbol)
79 |
80 | assert.strictEqual(approved1, approved2, ` ${symbol} token should not change approval`)
81 | assert.isFalse(approved2, `${symbol} token shouldn't be approved yet`)
82 | })))
83 |
84 | it('owner can set token approval', () => Promise.all(testingTokens.map(async token => {
85 | const symbol = await token.symbol.call()
86 | const approved1 = await getAndPrintApproval(token, symbol)
87 | assert.isFalse(approved1, `${symbol} token is not approved`)
88 |
89 | await assertIsOwner(master)
90 |
91 | logger(`Owner changes ${symbol} approval to ${!approved1}`)
92 |
93 | await dx.updateApprovalOfToken([token.address], !approved1, { from: master })
94 |
95 | const approved2 = await getAndPrintApproval(token, symbol)
96 |
97 | assert.strictEqual(!approved1, approved2, ` ${symbol} token should change approval`)
98 | assert.isTrue(approved2, `${symbol} token should be approved`)
99 | })))
100 |
101 | it('not owner can\'t remove token approval', () => Promise.all(testingTokens.map(async token => {
102 | const symbol = await token.symbol.call()
103 | const approved1 = await getAndPrintApproval(token, symbol)
104 | assert.isTrue(approved1, `${symbol} token is approved`)
105 |
106 | await assertIsNotOwner(seller1)
107 |
108 | logger(`Not owner tries to change ${symbol} approval to ${!approved1}`)
109 |
110 | await assertRejects(dx.updateApprovalOfToken([token.address], !approved1, { from: seller1 }), `not owner can't remove ${symbol} token approval`)
111 |
112 | const approved2 = await getAndPrintApproval(token, symbol)
113 |
114 | assert.strictEqual(approved1, approved2, ` ${symbol} token should not change approval`)
115 | assert.isTrue(approved2, `${symbol} token should still be approved`)
116 | })))
117 |
118 | it('owner can remove token approval', () => Promise.all(testingTokens.map(async token => {
119 | const symbol = await token.symbol.call()
120 | const approved1 = await getAndPrintApproval(token, symbol)
121 | assert.isTrue(approved1, `${symbol} token is approved`)
122 |
123 | await assertIsOwner(master)
124 |
125 | logger(`Owner changes ${symbol} approval to ${!approved1}`)
126 |
127 | await dx.updateApprovalOfToken([token.address], !approved1, { from: master })
128 |
129 | const approved2 = await getAndPrintApproval(token, symbol)
130 |
131 | assert.strictEqual(!approved1, approved2, ` ${symbol} token should change approval`)
132 | assert.isFalse(approved2, `${symbol} token should be unapproved`)
133 | })))
134 | })
135 |
--------------------------------------------------------------------------------
/test/dutchExchange-UpdateExchangeParams.spec.js:
--------------------------------------------------------------------------------
1 | /* global contract, assert, artifacts */
2 | /* eslint no-undef: "error" */
3 |
4 | const {
5 | logger,
6 | assertRejects,
7 | gasLogger
8 | } = require('./utils')
9 |
10 | const {
11 | getContracts,
12 | wait
13 | } = require('./testFunctions')
14 |
15 | const PriceOracleInterface = artifacts.require('PriceOracleInterface')
16 |
17 | // Test VARS
18 | let newPO
19 | let dx
20 | let medianizer
21 | let params2
22 | let contracts
23 |
24 | contract('DutchExchange updating exchange params', accounts => {
25 | const [master, seller1] = accounts
26 |
27 | afterEach(gasLogger)
28 |
29 | before(async () => {
30 | // get contractsU
31 | contracts = await getContracts({ resetCache: true });
32 | // destructure contracts into upper state
33 | ({
34 | DutchExchange: dx,
35 | Medianizer: medianizer
36 | } = contracts)
37 |
38 | // a new deployed PriceOracleInterface to replace the old with
39 | contracts.newPO = await PriceOracleInterface.new(master, medianizer.address);
40 | ({ newPO } = contracts)
41 |
42 | params2 = {
43 | auctioneer: seller1,
44 | ethUSDOracle: newPO.address,
45 | thresholdNewTokenPair: '5000',
46 | thresholdNewAuction: '500'
47 | }
48 | })
49 |
50 | const getExchangeParams = async () => {
51 | const [auctioneer, ethUSDOracle, thresholdNewTokenPair, thresholdNewAuction] = await Promise.all([
52 | dx.auctioneer.call(),
53 | dx.ethUSDOracle.call(),
54 | dx.thresholdNewTokenPair.call(),
55 | dx.thresholdNewAuction.call()
56 | ])
57 |
58 | return {
59 | auctioneer,
60 | ethUSDOracle,
61 | thresholdNewTokenPair: thresholdNewTokenPair.toString(),
62 | thresholdNewAuction: thresholdNewAuction.toString()
63 | }
64 | }
65 |
66 | const getAndPrintExchangeParams = async () => {
67 | const params = await getExchangeParams()
68 | const {
69 | auctioneer,
70 | ethUSDOracle,
71 | thresholdNewTokenPair,
72 | thresholdNewAuction
73 | } = params
74 |
75 | logger(`DutchExchange parameters:
76 | auctioneer: ${auctioneer},
77 | ethUSDOracle: ${ethUSDOracle},
78 | thresholdNewTokenPair: ${thresholdNewTokenPair},
79 | thresholdNewAuction: ${thresholdNewAuction}
80 | `)
81 |
82 | return params
83 | }
84 |
85 | const assertIsAuctioneer = async acc => {
86 | const auctioneer = await dx.auctioneer.call()
87 | assert.strictEqual(auctioneer, acc, 'account should be DutchExchange contract auctioneer')
88 | }
89 |
90 | const assertIsNotAuctioneer = async acc => {
91 | const auctioneer = await dx.auctioneer.call()
92 | assert.notStrictEqual(auctioneer, acc, 'account should not be DutchExchange contract auctioneer')
93 | }
94 |
95 | it('not auctioneer can\'t change params', async () => {
96 | const params1 = await getAndPrintExchangeParams()
97 |
98 | await assertIsNotAuctioneer(seller1)
99 | assert.notDeepEqual(params1, params2, 'parameters must be different')
100 |
101 | logger(`Not auctioneer tries to change params to ${JSON.stringify(params2, null, 5)}`)
102 | await assertRejects(dx.updateAuctioneer(params2.auctioneer, { from: seller1 }), 'not auctioneer can\'t change params')
103 | await assertRejects(dx.initiateEthUsdOracleUpdate({ from: seller1 }), 'not auctioneer can\'t change params')
104 | await assertRejects(dx.updateEthUSDOracle(params2.ethUSDOracle, { from: seller1 }), 'not auctioneer can\'t change params')
105 | await assertRejects(dx.updateThresholdNewTokenPair(params2.thresholdNewTokenPair, { from: seller1 }), 'not auctioneer can\'t change params')
106 | await assertRejects(dx.updateThresholdNewAuction(params2.thresholdNewAuction, { from: seller1 }), 'not auctioneer can\'t change params')
107 |
108 | assert.deepEqual(params1, await getAndPrintExchangeParams(), 'exchange params should stay the same')
109 | })
110 | it('price oracle can not be changed immediately params', async () => {
111 | const params1 = await getAndPrintExchangeParams()
112 |
113 | await assertIsAuctioneer(master)
114 | logger(`initiating oracle address update to ${params2.ethUSDOracle}`)
115 | await dx.initiateEthUsdOracleUpdate(params2.ethUSDOracle, { from: master })
116 | await assertRejects(dx.updateEthUSDOracle({ from: master }), 'to early to change oracle interface')
117 | })
118 | it('auctioneer can change params', async () => {
119 | const params1 = await getAndPrintExchangeParams()
120 |
121 | await assertIsAuctioneer(master)
122 |
123 | assert.notDeepEqual(params1, params2, 'parameters must be different')
124 | await wait(60 * 60 * 24 * 30 + 5)
125 | logger(`auctioneer changes params to ${JSON.stringify(params2, null, 5)}`)
126 | await dx.updateEthUSDOracle({ from: master })
127 | await dx.updateThresholdNewTokenPair(params2.thresholdNewTokenPair, { from: master })
128 | await dx.updateThresholdNewAuction(params2.thresholdNewAuction, { from: master })
129 | await dx.updateAuctioneer(params2.auctioneer, { from: master })
130 |
131 | assert.deepEqual(params2, await getAndPrintExchangeParams(), 'exchange params should be changed')
132 | })
133 | })
134 |
--------------------------------------------------------------------------------
/contracts/TokenFRT.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.2;
2 |
3 | import "@gnosis.pm/util-contracts/contracts/Proxy.sol";
4 | import "@gnosis.pm/util-contracts/contracts/GnosisStandardToken.sol";
5 |
6 |
7 | /// @title Standard token contract with overflow protection
8 | contract TokenFRT is Proxied, GnosisStandardToken {
9 | address public owner;
10 |
11 | string public constant symbol = "MGN";
12 | string public constant name = "Magnolia Token";
13 | uint8 public constant decimals = 18;
14 |
15 | struct UnlockedToken {
16 | uint amountUnlocked;
17 | uint withdrawalTime;
18 | }
19 |
20 | /*
21 | * Storage
22 | */
23 | address public minter;
24 |
25 | // user => UnlockedToken
26 | mapping(address => UnlockedToken) public unlockedTokens;
27 |
28 | // user => amount
29 | mapping(address => uint) public lockedTokenBalances;
30 |
31 | /*
32 | * Public functions
33 | */
34 |
35 | // @dev allows to set the minter of Magnolia tokens once.
36 | // @param _minter the minter of the Magnolia tokens, should be the DX-proxy
37 | function updateMinter(address _minter) public {
38 | require(msg.sender == owner, "Only the minter can set a new one");
39 | require(_minter != address(0), "The new minter must be a valid address");
40 |
41 | minter = _minter;
42 | }
43 |
44 | // @dev the intention is to set the owner as the DX-proxy, once it is deployed
45 | // Then only an update of the DX-proxy contract after a 30 days delay could change the minter again.
46 | function updateOwner(address _owner) public {
47 | require(msg.sender == owner, "Only the owner can update the owner");
48 | require(_owner != address(0), "The new owner must be a valid address");
49 | owner = _owner;
50 | }
51 |
52 | function mintTokens(address user, uint amount) public {
53 | require(msg.sender == minter, "Only the minter can mint tokens");
54 |
55 | lockedTokenBalances[user] = add(lockedTokenBalances[user], amount);
56 | totalTokens = add(totalTokens, amount);
57 | }
58 |
59 | /// @dev Lock Token
60 | function lockTokens(uint amount) public returns (uint totalAmountLocked) {
61 | // Adjust amount by balance
62 | uint actualAmount = min(amount, balances[msg.sender]);
63 |
64 | // Update state variables
65 | balances[msg.sender] = sub(balances[msg.sender], actualAmount);
66 | lockedTokenBalances[msg.sender] = add(lockedTokenBalances[msg.sender], actualAmount);
67 |
68 | // Get return variable
69 | totalAmountLocked = lockedTokenBalances[msg.sender];
70 | }
71 |
72 | function unlockTokens() public returns (uint totalAmountUnlocked, uint withdrawalTime) {
73 | // Adjust amount by locked balances
74 | uint amount = lockedTokenBalances[msg.sender];
75 |
76 | if (amount > 0) {
77 | // Update state variables
78 | lockedTokenBalances[msg.sender] = sub(lockedTokenBalances[msg.sender], amount);
79 | unlockedTokens[msg.sender].amountUnlocked = add(unlockedTokens[msg.sender].amountUnlocked, amount);
80 | unlockedTokens[msg.sender].withdrawalTime = now + 24 hours;
81 | }
82 |
83 | // Get return variables
84 | totalAmountUnlocked = unlockedTokens[msg.sender].amountUnlocked;
85 | withdrawalTime = unlockedTokens[msg.sender].withdrawalTime;
86 | }
87 |
88 | function withdrawUnlockedTokens() public {
89 | require(unlockedTokens[msg.sender].withdrawalTime < now, "The tokens cannot be withdrawn yet");
90 | balances[msg.sender] = add(balances[msg.sender], unlockedTokens[msg.sender].amountUnlocked);
91 | unlockedTokens[msg.sender].amountUnlocked = 0;
92 | }
93 |
94 | function min(uint a, uint b) public pure returns (uint) {
95 | if (a < b) {
96 | return a;
97 | } else {
98 | return b;
99 | }
100 | }
101 |
102 | /// @dev Returns whether an add operation causes an overflow
103 | /// @param a First addend
104 | /// @param b Second addend
105 | /// @return Did no overflow occur?
106 | function safeToAdd(uint a, uint b) public pure returns (bool) {
107 | return a + b >= a;
108 | }
109 |
110 | /// @dev Returns whether a subtraction operation causes an underflow
111 | /// @param a Minuend
112 | /// @param b Subtrahend
113 | /// @return Did no underflow occur?
114 | function safeToSub(uint a, uint b) public pure returns (bool) {
115 | return a >= b;
116 | }
117 |
118 | /// @dev Returns sum if no overflow occurred
119 | /// @param a First addend
120 | /// @param b Second addend
121 | /// @return Sum
122 | function add(uint a, uint b) public pure returns (uint) {
123 | require(safeToAdd(a, b), "It must be a safe adition");
124 | return a + b;
125 | }
126 |
127 | /// @dev Returns difference if no overflow occurred
128 | /// @param a Minuend
129 | /// @param b Subtrahend
130 | /// @return Difference
131 | function sub(uint a, uint b) public pure returns (uint) {
132 | require(safeToSub(a, b), "It must be a safe substraction");
133 | return a - b;
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/test/dutchExchange-Proxy.spec.js:
--------------------------------------------------------------------------------
1 | /* global contract, assert, artifacts */
2 | /* eslint no-undef: "error" */
3 |
4 | const {
5 | log: utilsLog,
6 | assertRejects,
7 | gasLogger
8 | } = require('./utils')
9 |
10 | const { getContracts, wait } = require('./testFunctions')
11 |
12 | const InternalTests = artifacts.require('InternalTests')
13 |
14 | // Test VARS
15 | let dx, dxNew, ethToken
16 | let pr
17 |
18 | let contracts
19 |
20 | const separateLogs = () => utilsLog('\n ----------------------------------')
21 | const log = (...args) => utilsLog('\t', ...args)
22 |
23 | contract('DutchExchange - Proxy', accounts => {
24 | const [master, seller1] = accounts
25 |
26 | beforeEach(separateLogs)
27 | afterEach(gasLogger)
28 |
29 | before(async () => {
30 | // get contractsU
31 | contracts = await getContracts({ resetCache: true });
32 | // destructure contracts into upper state
33 | ({
34 | DutchExchange: dx,
35 | EtherToken: ethToken,
36 | // dxNew has new code as it is an InternalTests contract
37 | DutchExchangeProxy: pr
38 | } = contracts)
39 | const initParams = await getExchangeParams(dx)
40 | dxNew = await InternalTests.new(...initParams)
41 | })
42 |
43 | const getExchangeParams = async (dxContr = dx) => {
44 | const [frtToken,
45 | owlToken,
46 | auctioneer,
47 | eth,
48 | ethUSDOracle,
49 | thresholdNewTokenPair,
50 | thresholdNewAuction] = await Promise.all([
51 | dxContr.frtToken.call(),
52 | dxContr.owlToken.call(),
53 | dxContr.auctioneer.call(),
54 | dxContr.ethToken.call(),
55 | dxContr.ethUSDOracle.call(),
56 | dxContr.thresholdNewTokenPair.call(),
57 | dxContr.thresholdNewAuction.call()
58 | ])
59 |
60 | return [
61 | frtToken,
62 | owlToken,
63 | auctioneer,
64 | eth,
65 | ethUSDOracle,
66 | thresholdNewTokenPair,
67 | thresholdNewAuction
68 | ]
69 | }
70 |
71 | const assertIsAuctioneer = async acc => {
72 | const auctioneer = await dx.auctioneer.call()
73 | assert.strictEqual(auctioneer, acc, 'account should be DutchExchange contract auctioneer')
74 | }
75 |
76 | const assertIsNotAuctioneer = async acc => {
77 | const auctioneer = await dx.auctioneer.call()
78 | assert.notStrictEqual(auctioneer, acc, 'account should not be DutchExchange contract auctioneer')
79 | }
80 |
81 | it('DutchExchange is initialized and params are set', async () => {
82 | const ethTokenAddress = await dx.ethToken.call()
83 | assert.strictEqual(ethTokenAddress, ethToken.address, 'DutchExchange should be initialized')
84 |
85 | const params = await getExchangeParams()
86 | assert.isTrue(Object.values(params).every(param => !!+param), 'No zero-initialized parameters')
87 | })
88 |
89 | it('masterCopy can\'t be updated before masterCopyCountdown was started', async () => {
90 | await assertIsAuctioneer(master)
91 | log('calling dx.updateMasterCopy() as auctioneer')
92 | await assertRejects(dx.updateMasterCopy({ from: master }), 'should reject as startMasterCopyCountdown wasn\'t yet called')
93 | log('tx was rejected')
94 | })
95 |
96 | it('not auctioneer can\'t call startMasterCopyCountdown', async () => {
97 | await assertIsNotAuctioneer(seller1)
98 | log('calling dx.startMasterCopyCountdown() as not auctioneer')
99 | await assertRejects(dx.startMasterCopyCountdown(dxNew.address, { from: seller1 }), 'should reject as caller isn\'t the auctioneer')
100 | log('tx was rejected')
101 | })
102 |
103 | it('can\'t call startMasterCopyCountdown with zero dx address', async () => {
104 | await assertIsAuctioneer(master)
105 | log('calling dx.startMasterCopyCountdown() with dx address == 0')
106 | await assertRejects(dx.startMasterCopyCountdown(0, { from: master }), 'should reject as caller isn\'t the auctioneer')
107 | log('tx was rejected')
108 | })
109 |
110 | it('auctioneer can call startMasterCopyCountdown', async () => {
111 | await assertIsAuctioneer(master)
112 | log('calling dx.startMasterCopyCountdown() as auctioneer with valid dx address')
113 | await dx.startMasterCopyCountdown(dxNew.address, { from: master })
114 | })
115 |
116 | it('auctioneer can\'t update masterCopy before time limit', async () => {
117 | await assertIsAuctioneer(master)
118 | log('calling dx.updateMasterCopy() as auctioneer before time limit')
119 | await assertRejects(dx.updateMasterCopy({ from: master }), 'should reject as time hasn\t passed')
120 | log('tx was rejected')
121 | })
122 |
123 | it('any user can update masterCopy after time limit', async () => {
124 | await wait(60 * 60 * 24 * 30)
125 | await assertIsNotAuctioneer(seller1)
126 | const params1 = await getExchangeParams()
127 |
128 | assert.notEqual(await dx.getMasterCopy(), dxNew.address, 'address should not yet be the same')
129 | log(`DutchExchange contract is at the ${dx.address} address`)
130 |
131 | log('calling dx.updateMasterCopy() as not auctioneer after time limit')
132 | await dx.updateMasterCopy({ from: seller1 })
133 |
134 | // using a new interface as masterCopy is an InternalTests now
135 | const ndx = await InternalTests.at(pr.address)
136 | const params2 = await getExchangeParams(ndx)
137 | assert.deepEqual(params1, params2, 'exchange params should stay the same')
138 |
139 | assert.strictEqual(await ndx.getMasterCopy.call(), dxNew.address, 'masterCopy address should have changed')
140 | log(`DutchExchange contract is now at the ${dxNew.address} address`)
141 | })
142 | })
143 |
--------------------------------------------------------------------------------