aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.prettierignore2
-rw-r--r--packages/0x.js/package.json2
-rw-r--r--packages/abi-gen/src/index.ts4
-rw-r--r--packages/contracts/compiler.json33
-rw-r--r--packages/contracts/package.json7
-rw-r--r--packages/contracts/test/multi_sig_with_time_lock.ts2
-rw-r--r--packages/contracts/test/multi_sig_with_time_lock_except_remove_auth_addr.ts5
-rw-r--r--packages/contracts/util/artifacts.ts24
-rw-r--r--packages/contracts/util/types.ts16
-rw-r--r--packages/deployer/src/cli.ts100
-rw-r--r--packages/deployer/src/compiler.ts130
-rw-r--r--packages/deployer/src/deployer.ts54
-rw-r--r--packages/deployer/src/index.ts1
-rw-r--r--packages/deployer/src/utils/constants.ts1
-rw-r--r--packages/deployer/src/utils/types.ts53
-rw-r--r--packages/deployer/test/compiler_test.ts7
-rw-r--r--packages/deployer/test/deployer_test.ts9
-rw-r--r--packages/deployer/test/fixtures/exchange_bin.ts2
-rw-r--r--packages/deployer/test/util/constants.ts2
-rw-r--r--packages/dev-utils/src/coverage.ts2
-rw-r--r--packages/metacoin/compiler.json15
-rw-r--r--packages/metacoin/package.json4
-rw-r--r--packages/migrations/artifacts/1.0.0/.gitkeep0
-rw-r--r--packages/sol-cov/compiler.json18
-rw-r--r--packages/sol-cov/package.json2
-rw-r--r--packages/sol-cov/src/collect_contract_data.ts25
-rw-r--r--packages/sol-cov/src/coverage_manager.ts57
-rw-r--r--packages/sol-cov/src/utils.ts4
-rw-r--r--packages/sol-resolver/src/index.ts1
-rw-r--r--packages/sol-resolver/src/resolvers/name_resolver.ts13
-rw-r--r--packages/sol-resolver/src/resolvers/relative_fs_resolver.ts26
-rw-r--r--packages/typescript-typings/types/solc/index.d.ts70
-rw-r--r--packages/website/public/images/landing/project_logos/the_ocean.pngbin4766 -> 6322 bytes
-rw-r--r--packages/website/ts/components/legacy_portal/legacy_portal.tsx47
-rw-r--r--packages/website/ts/components/legacy_portal/legacy_portal_menu.tsx20
-rw-r--r--packages/website/ts/components/portal/portal.tsx263
-rw-r--r--packages/website/ts/components/relayer_index/relayer_grid_tile.tsx102
-rw-r--r--packages/website/ts/components/relayer_index/relayer_index.tsx70
-rw-r--r--packages/website/ts/components/relayer_index/relayer_top_tokens.tsx16
-rw-r--r--packages/website/ts/components/top_bar/provider_display.tsx36
-rw-r--r--packages/website/ts/components/top_bar/top_bar.tsx68
-rw-r--r--packages/website/ts/components/wallet/wallet.tsx67
-rw-r--r--packages/website/ts/containers/portal.ts88
-rw-r--r--packages/website/ts/index.tsx11
-rw-r--r--packages/website/ts/types.ts11
46 files changed, 983 insertions, 509 deletions
diff --git a/.gitignore b/.gitignore
index e798e3a0a..ab90e9e17 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,7 +79,7 @@ packages/metacoin/artifacts
packages/0x.js/test/artifacts
packages/order-watcher/test/artifacts
packages/contract-wrappers/test/artifacts
-packages/migrations/src/artifacts
+packages/migrations/artifacts
# generated contract wrappers
packages/0x.js/src/contract_wrappers/generated/
diff --git a/.prettierignore b/.prettierignore
index 024d0b548..f12fdf870 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -2,6 +2,6 @@ lib
.nyc_output
/packages/contracts/src/artifacts
/packages/metacoin/artifacts
-/packages/migrations/src/artifacts
+/packages/migrations/artifacts/1.0.0
package.json
scripts/postpublish_utils.js
diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json
index 9fe2ec1a4..d1091b9e9 100644
--- a/packages/0x.js/package.json
+++ b/packages/0x.js/package.json
@@ -21,7 +21,7 @@
"test": "run-s clean test:commonjs",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
- "update_artifacts": "for i in ${npm_package_config_contracts}; do copyfiles -u 4 ../migrations/src/artifacts/$i.json test/artifacts; done;",
+ "update_artifacts": "for i in ${npm_package_config_contracts}; do copyfiles -u 4 ../migrations/artifacts/1.0.0/$i.json test/artifacts; done;",
"clean": "shx rm -rf _bundles lib test_temp scripts",
"build:umd:prod": "NODE_ENV=production webpack",
"build:commonjs": "tsc && yarn update_artifacts && copyfiles -u 2 './src/compact_artifacts/**/*.json' ./lib/src/compact_artifacts && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
diff --git a/packages/abi-gen/src/index.ts b/packages/abi-gen/src/index.ts
index ecef33b16..7125171b9 100644
--- a/packages/abi-gen/src/index.ts
+++ b/packages/abi-gen/src/index.ts
@@ -108,8 +108,8 @@ for (const abiFileName of abiFileNames) {
ABI = parsedContent; // ABI file
} else if (!_.isUndefined(parsedContent.abi)) {
ABI = parsedContent.abi; // Truffle artifact
- } else if (!_.isUndefined(parsedContent.networks) && !_.isUndefined(parsedContent.networks[args.networkId])) {
- ABI = parsedContent.networks[args.networkId].abi; // 0x contracts package artifact
+ } else if (!_.isUndefined(parsedContent.compilerOutput.abi)) {
+ ABI = parsedContent.compilerOutput.abi; // 0x artifact
}
if (_.isUndefined(ABI)) {
logUtils.log(`${chalk.red(`ABI not found in ${abiFileName}.`)}`);
diff --git a/packages/contracts/compiler.json b/packages/contracts/compiler.json
new file mode 100644
index 000000000..493d6373d
--- /dev/null
+++ b/packages/contracts/compiler.json
@@ -0,0 +1,33 @@
+{
+ "artifactsDir": "../migrations/artifacts/1.0.0",
+ "contractsDir": "src/contracts",
+ "compilerSettings": {
+ "outputSelection": {
+ "*": {
+ "*": [
+ "abi",
+ "evm.bytecode.object",
+ "evm.bytecode.sourceMap",
+ "evm.deployedBytecode.object",
+ "evm.deployedBytecode.sourceMap"
+ ]
+ }
+ }
+ },
+ "contracts": [
+ "Exchange",
+ "DummyToken",
+ "ZRXToken",
+ "Token",
+ "WETH9",
+ "TokenTransferProxy",
+ "MultiSigWallet",
+ "MultiSigWalletWithTimeLock",
+ "MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress",
+ "MaliciousToken",
+ "TokenRegistry",
+ "Arbitrage",
+ "EtherDelta",
+ "AccountLevels"
+ ]
+}
diff --git a/packages/contracts/package.json b/packages/contracts/package.json
index 6d51d71cb..c47518f17 100644
--- a/packages/contracts/package.json
+++ b/packages/contracts/package.json
@@ -10,13 +10,13 @@
"scripts": {
"build:watch": "tsc -w",
"prebuild": "run-s clean compile copy_artifacts generate_contract_wrappers",
- "copy_artifacts": "copyfiles -u 4 '../migrations/src/artifacts/**/*' ./lib/src/artifacts;",
+ "copy_artifacts": "copyfiles -u 4 '../migrations/artifacts/1.0.0/**/*' ./lib/src/artifacts;",
"build": "tsc",
"test": "run-s build run_mocha",
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
"run_mocha": "mocha 'lib/test/**/*.js' --timeout 100000 --bail --exit",
"compile:comment": "Yarn workspaces do not link binaries correctly so we need to reference them directly https://github.com/yarnpkg/yarn/issues/3846",
- "compile": "node ../deployer/lib/src/cli.js compile --contracts ${npm_package_config_contracts} --contracts-dir src/contracts --artifacts-dir ../migrations/src/artifacts",
+ "compile": "node ../deployer/lib/src/cli.js compile",
"clean": "shx rm -rf ./lib",
"generate_contract_wrappers": "node ../abi-gen/lib/index.js --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers/generated --backend ethers && prettier --write 'src/contract_wrappers/generated/**.ts'",
"lint": "tslint --project . 'migrations/**/*.ts' 'test/**/*.ts' 'util/**/*.ts' 'deploy/**/*.ts'",
@@ -26,8 +26,7 @@
"test:circleci": "yarn test:coverage"
},
"config": {
- "abis": "../migrations/src/artifacts/@(DummyToken|TokenTransferProxy|Exchange|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|Arbitrage|EtherDelta|AccountLevels).json",
- "contracts": "Exchange,DummyToken,ZRXToken,Token,WETH9,TokenTransferProxy,MultiSigWallet,MultiSigWalletWithTimeLock,MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,MaliciousToken,TokenRegistry,Arbitrage,EtherDelta,AccountLevels"
+ "abis": "../migrations/artifacts/1.0.0/@(DummyToken|TokenTransferProxy|Exchange|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|Arbitrage|EtherDelta|AccountLevels).json"
},
"repository": {
"type": "git",
diff --git a/packages/contracts/test/multi_sig_with_time_lock.ts b/packages/contracts/test/multi_sig_with_time_lock.ts
index 0f1e3bd11..cf3893780 100644
--- a/packages/contracts/test/multi_sig_with_time_lock.ts
+++ b/packages/contracts/test/multi_sig_with_time_lock.ts
@@ -17,7 +17,7 @@ import { chaiSetup } from './utils/chai_setup';
import { deployer } from './utils/deployer';
import { provider, web3Wrapper } from './utils/web3_wrapper';
-const MULTI_SIG_ABI = artifacts.MultiSigWalletWithTimeLock.networks[constants.TESTRPC_NETWORK_ID].abi;
+const MULTI_SIG_ABI = artifacts.MultiSigWalletWithTimeLock.compilerOutput.abi;
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
diff --git a/packages/contracts/test/multi_sig_with_time_lock_except_remove_auth_addr.ts b/packages/contracts/test/multi_sig_with_time_lock_except_remove_auth_addr.ts
index 006d7f3c6..3ff5b82ed 100644
--- a/packages/contracts/test/multi_sig_with_time_lock_except_remove_auth_addr.ts
+++ b/packages/contracts/test/multi_sig_with_time_lock_except_remove_auth_addr.ts
@@ -17,10 +17,9 @@ import { ContractName, SubmissionContractEventArgs, TransactionDataParams } from
import { chaiSetup } from './utils/chai_setup';
import { deployer } from './utils/deployer';
import { provider, web3Wrapper } from './utils/web3_wrapper';
-const PROXY_ABI = artifacts.TokenTransferProxy.networks[constants.TESTRPC_NETWORK_ID].abi;
+const PROXY_ABI = artifacts.TokenTransferProxy.compilerOutput.abi;
const MUTISIG_WALLET_WITH_TIME_LOCK_EXCEPT_REMOVE_AUTHORIZED_ADDRESS_ABI =
- artifacts.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.networks[constants.TESTRPC_NETWORK_ID]
- .abi;
+ artifacts.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.compilerOutput.abi;
chaiSetup.configure();
const expect = chai.expect;
diff --git a/packages/contracts/util/artifacts.ts b/packages/contracts/util/artifacts.ts
index f427c6d9a..d262b8058 100644
--- a/packages/contracts/util/artifacts.ts
+++ b/packages/contracts/util/artifacts.ts
@@ -1,3 +1,5 @@
+import { ContractArtifact } from '@0xproject/deployer';
+
import * as DummyToken from '../src/artifacts/DummyToken.json';
import * as Exchange from '../src/artifacts/Exchange.json';
import * as MaliciousToken from '../src/artifacts/MaliciousToken.json';
@@ -9,17 +11,15 @@ import * as TokenTransferProxy from '../src/artifacts/TokenTransferProxy.json';
import * as EtherToken from '../src/artifacts/WETH9.json';
import * as ZRX from '../src/artifacts/ZRXToken.json';
-import { Artifact } from './types';
-
export const artifacts = {
- ZRX: (ZRX as any) as Artifact,
- DummyToken: (DummyToken as any) as Artifact,
- Token: (Token as any) as Artifact,
- Exchange: (Exchange as any) as Artifact,
- EtherToken: (EtherToken as any) as Artifact,
- TokenRegistry: (TokenRegistry as any) as Artifact,
- MaliciousToken: (MaliciousToken as any) as Artifact,
- TokenTransferProxy: (TokenTransferProxy as any) as Artifact,
- MultiSigWalletWithTimeLock: (MultiSigWalletWithTimeLock as any) as Artifact,
- MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress: (MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress as any) as Artifact,
+ ZRX: (ZRX as any) as ContractArtifact,
+ DummyToken: (DummyToken as any) as ContractArtifact,
+ Token: (Token as any) as ContractArtifact,
+ Exchange: (Exchange as any) as ContractArtifact,
+ EtherToken: (EtherToken as any) as ContractArtifact,
+ TokenRegistry: (TokenRegistry as any) as ContractArtifact,
+ MaliciousToken: (MaliciousToken as any) as ContractArtifact,
+ TokenTransferProxy: (TokenTransferProxy as any) as ContractArtifact,
+ MultiSigWalletWithTimeLock: (MultiSigWalletWithTimeLock as any) as ContractArtifact,
+ MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress: (MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress as any) as ContractArtifact,
};
diff --git a/packages/contracts/util/types.ts b/packages/contracts/util/types.ts
index 321084c42..9bc412433 100644
--- a/packages/contracts/util/types.ts
+++ b/packages/contracts/util/types.ts
@@ -100,19 +100,3 @@ export enum ContractName {
EtherDelta = 'EtherDelta',
Arbitrage = 'Arbitrage',
}
-
-export interface Artifact {
- contract_name: ContractName;
- networks: {
- [networkId: number]: {
- abi: ContractAbi;
- solc_version: string;
- keccak256: string;
- optimizer_enabled: number;
- unlinked_binary: string;
- updated_at: number;
- address: string;
- constructor_args: string;
- };
- };
-}
diff --git a/packages/deployer/src/cli.ts b/packages/deployer/src/cli.ts
index 7f1ae708a..8c89cf382 100644
--- a/packages/deployer/src/cli.ts
+++ b/packages/deployer/src/cli.ts
@@ -13,13 +13,13 @@ import { constants } from './utils/constants';
import { consoleReporter } from './utils/error_reporter';
import { CliOptions, CompilerOptions, DeployerOptions } from './utils/types';
-const DEFAULT_OPTIMIZER_ENABLED = false;
const DEFAULT_CONTRACTS_DIR = path.resolve('src/contracts');
const DEFAULT_ARTIFACTS_DIR = path.resolve('src/artifacts');
const DEFAULT_NETWORK_ID = 50;
const DEFAULT_JSONRPC_URL = 'http://localhost:8545';
const DEFAULT_GAS_PRICE = (10 ** 9 * 2).toString();
const DEFAULT_CONTRACTS_LIST = '*';
+const SEPARATOR = ',';
/**
* Compiles all contracts with options passed in through CLI.
@@ -28,10 +28,8 @@ const DEFAULT_CONTRACTS_LIST = '*';
async function onCompileCommandAsync(argv: CliOptions): Promise<void> {
const opts: CompilerOptions = {
contractsDir: argv.contractsDir,
- networkId: argv.networkId,
- optimizerEnabled: argv.shouldOptimize,
artifactsDir: argv.artifactsDir,
- specifiedContracts: getContractsSetFromList(argv.contracts),
+ contracts: argv.contracts === DEFAULT_CONTRACTS_LIST ? DEFAULT_CONTRACTS_LIST : argv.contracts.split(SEPARATOR),
};
await commands.compileAsync(opts);
}
@@ -46,10 +44,8 @@ async function onDeployCommandAsync(argv: CliOptions): Promise<void> {
const networkId = await web3Wrapper.getNetworkIdAsync();
const compilerOpts: CompilerOptions = {
contractsDir: argv.contractsDir,
- networkId,
- optimizerEnabled: argv.shouldOptimize,
artifactsDir: argv.artifactsDir,
- specifiedContracts: getContractsSetFromList(argv.contracts),
+ contracts: argv.contracts === DEFAULT_CONTRACTS_LIST ? DEFAULT_CONTRACTS_LIST : argv.contracts.split(SEPARATOR),
};
await commands.compileAsync(compilerOpts);
@@ -58,91 +54,79 @@ async function onDeployCommandAsync(argv: CliOptions): Promise<void> {
from: argv.account,
};
const deployerOpts: DeployerOptions = {
- artifactsDir: argv.artifactsDir,
+ artifactsDir: argv.artifactsDir || DEFAULT_ARTIFACTS_DIR,
jsonrpcUrl: argv.jsonrpcUrl,
networkId,
defaults,
};
- const deployerArgsString = argv.args as string;
- const deployerArgs = deployerArgsString.split(',');
+ const deployerArgsString = argv.constructorArgs as string;
+ const deployerArgs = deployerArgsString.split(SEPARATOR);
await commands.deployAsync(argv.contract as string, deployerArgs, deployerOpts);
}
/**
- * Creates a set of contracts to compile.
- * @param contracts Comma separated list of contracts to compile
- */
-function getContractsSetFromList(contracts: string): Set<string> {
- const specifiedContracts = new Set();
- if (contracts === '*') {
- return new Set(['*']);
- }
- const contractsArray = contracts.split(',');
- _.forEach(contractsArray, contractName => {
- specifiedContracts.add(contractName);
- });
- return specifiedContracts;
-}
-/**
- * Provides extra required options for deploy command.
+ * Adds additional required options for when the user is calling the deploy command.
* @param yargsInstance yargs instance provided in builder function callback.
*/
function deployCommandBuilder(yargsInstance: any) {
return yargsInstance
- .option('contract', {
- type: 'string',
- description: 'name of contract to deploy, exluding .sol extension',
- })
- .option('args', {
- type: 'string',
- description: 'comma separated list of constructor args to deploy contract with',
- })
- .demandOption(['contract', 'args'])
- .help().argv;
-}
-
-(() => {
- const identityCommandBuilder = _.identity;
- return yargs
- .option('contracts-dir', {
- type: 'string',
- default: DEFAULT_CONTRACTS_DIR,
- description: 'path of contracts directory to compile',
- })
.option('network-id', {
type: 'number',
default: DEFAULT_NETWORK_ID,
description: 'mainnet=1, kovan=42, testrpc=50',
})
- .option('should-optimize', {
- type: 'boolean',
- default: DEFAULT_OPTIMIZER_ENABLED,
- description: 'enable optimizer',
+ .option('contract', {
+ type: 'string',
+ description: 'name of contract to deploy, excluding .sol extension',
})
- .option('artifacts-dir', {
+ .option('constructor-args', {
type: 'string',
- default: DEFAULT_ARTIFACTS_DIR,
- description: 'path to write contracts artifacts to',
+ description: 'comma separated list of constructor args to deploy contract with',
})
.option('jsonrpc-url', {
type: 'string',
default: DEFAULT_JSONRPC_URL,
description: 'url of JSON RPC',
})
+ .option('account', {
+ type: 'string',
+ description: 'account to use for deploying contracts',
+ })
.option('gas-price', {
type: 'string',
default: DEFAULT_GAS_PRICE,
description: 'gasPrice to be used for transactions',
})
- .option('account', {
- type: 'string',
- description: 'account to use for deploying contracts',
- })
+ .demandOption(['contract', 'args', 'account'])
+ .help().argv;
+}
+
+/**
+ * Adds additional required options for when the user is calling the compile command.
+ * @param yargsInstance yargs instance provided in builder function callback.
+ */
+function compileCommandBuilder(yargsInstance: any) {
+ return yargsInstance
.option('contracts', {
type: 'string',
default: DEFAULT_CONTRACTS_LIST,
description: 'comma separated list of contracts to compile',
})
- .command('compile', 'compile contracts', identityCommandBuilder, consoleReporter(onCompileCommandAsync))
+ .help().argv;
+}
+
+(() => {
+ const identityCommandBuilder = _.identity;
+ return yargs
+ .option('contracts-dir', {
+ type: 'string',
+ description: 'path of contracts directory to compile',
+ })
+ .option('artifacts-dir', {
+ type: 'string',
+ description: 'path to write contracts artifacts to',
+ })
+ .demandCommand(1)
+ .command('compile', 'compile contracts', compileCommandBuilder, consoleReporter(onCompileCommandAsync))
.command(
'deploy',
'deploy a single contract with provided arguments',
diff --git a/packages/deployer/src/compiler.ts b/packages/deployer/src/compiler.ts
index a3c8004ec..e81df3c0a 100644
--- a/packages/deployer/src/compiler.ts
+++ b/packages/deployer/src/compiler.ts
@@ -6,6 +6,7 @@ import {
FSResolver,
NameResolver,
NPMResolver,
+ RelativeFSResolver,
Resolver,
URLResolver,
} from '@0xproject/sol-resolver';
@@ -38,11 +39,30 @@ import {
ContractNetworks,
ContractSourceData,
ContractSpecificSourceData,
+ ContractVersionData,
} from './utils/types';
import { utils } from './utils/utils';
+type TYPE_ALL_FILES_IDENTIFIER = '*';
const ALL_CONTRACTS_IDENTIFIER = '*';
+const ALL_FILES_IDENTIFIER = '*';
const SOLC_BIN_DIR = path.join(__dirname, '..', '..', 'solc_bin');
+const DEFAULT_CONTRACTS_DIR = path.resolve('contracts');
+const DEFAULT_ARTIFACTS_DIR = path.resolve('artifacts');
+// Solc compiler settings cannot be configured from the commandline.
+// If you need this configured, please create a `compiler.json` config file
+// with your desired configurations.
+const DEFAULT_COMPILER_SETTINGS: solc.CompilerSettings = {
+ optimizer: {
+ enabled: false,
+ },
+ outputSelection: {
+ [ALL_FILES_IDENTIFIER]: {
+ [ALL_CONTRACTS_IDENTIFIER]: ['abi', 'evm.bytecode.object'],
+ },
+ },
+};
+const CONFIG_FILE = 'compiler.json';
/**
* The Compiler facilitates compiling Solidity smart contracts and saves the results
@@ -52,26 +72,28 @@ export class Compiler {
private _resolver: Resolver;
private _nameResolver: NameResolver;
private _contractsDir: string;
- private _networkId: number;
- private _optimizerEnabled: boolean;
+ private _compilerSettings: solc.CompilerSettings;
private _artifactsDir: string;
- private _specifiedContracts: Set<string> = new Set();
+ private _specifiedContracts: string[] | TYPE_ALL_FILES_IDENTIFIER;
/**
* Instantiates a new instance of the Compiler class.
- * @param opts Options specifying directories, network, and optimization settings.
* @return An instance of the Compiler class.
*/
constructor(opts: CompilerOptions) {
- this._contractsDir = opts.contractsDir;
- this._networkId = opts.networkId;
- this._optimizerEnabled = opts.optimizerEnabled;
- this._artifactsDir = opts.artifactsDir;
- this._specifiedContracts = opts.specifiedContracts;
+ // TODO: Look for config file in parent directories if not found in current directory
+ const config: CompilerOptions = fs.existsSync(CONFIG_FILE)
+ ? JSON.parse(fs.readFileSync(CONFIG_FILE).toString())
+ : {};
+ this._contractsDir = opts.contractsDir || config.contractsDir || DEFAULT_CONTRACTS_DIR;
+ this._compilerSettings = opts.compilerSettings || config.compilerSettings || DEFAULT_COMPILER_SETTINGS;
+ this._artifactsDir = opts.artifactsDir || config.artifactsDir || DEFAULT_ARTIFACTS_DIR;
+ this._specifiedContracts = opts.contracts || config.contracts || ALL_CONTRACTS_IDENTIFIER;
this._nameResolver = new NameResolver(path.resolve(this._contractsDir));
const resolver = new FallthroughResolver();
resolver.appendResolver(new URLResolver());
const packagePath = path.resolve('');
resolver.appendResolver(new NPMResolver(packagePath));
+ resolver.appendResolver(new RelativeFSResolver(this._contractsDir));
resolver.appendResolver(new FSResolver());
resolver.appendResolver(this._nameResolver);
this._resolver = resolver;
@@ -83,13 +105,13 @@ export class Compiler {
await createDirIfDoesNotExistAsync(this._artifactsDir);
await createDirIfDoesNotExistAsync(SOLC_BIN_DIR);
let contractNamesToCompile: string[] = [];
- if (this._specifiedContracts.has(ALL_CONTRACTS_IDENTIFIER)) {
+ if (this._specifiedContracts === ALL_CONTRACTS_IDENTIFIER) {
const allContracts = this._nameResolver.getAll();
contractNamesToCompile = _.map(allContracts, contractSource =>
path.basename(contractSource.path, constants.SOLIDITY_FILE_EXTENSION),
);
} else {
- contractNamesToCompile = Array.from(this._specifiedContracts.values());
+ contractNamesToCompile = this._specifiedContracts;
}
for (const contractNameToCompile of contractNamesToCompile) {
await this._compileContractAsync(contractNameToCompile);
@@ -101,17 +123,18 @@ export class Compiler {
*/
private async _compileContractAsync(contractName: string): Promise<void> {
const contractSource = this._resolver.resolve(contractName);
+ const absoluteContractPath = path.join(this._contractsDir, contractSource.path);
const currentArtifactIfExists = await getContractArtifactIfExistsAsync(this._artifactsDir, contractName);
- const sourceTreeHashHex = `0x${this._getSourceTreeHash(contractSource.path).toString('hex')}`;
-
+ const sourceTreeHashHex = `0x${this._getSourceTreeHash(absoluteContractPath).toString('hex')}`;
let shouldCompile = false;
if (_.isUndefined(currentArtifactIfExists)) {
shouldCompile = true;
} else {
const currentArtifact = currentArtifactIfExists as ContractArtifact;
- shouldCompile =
- currentArtifact.networks[this._networkId].optimizer_enabled !== this._optimizerEnabled ||
- currentArtifact.networks[this._networkId].source_tree_hash !== sourceTreeHashHex;
+ const isUserOnLatestVersion = currentArtifact.schemaVersion === constants.LATEST_ARTIFACT_VERSION;
+ const didCompilerSettingsChange = !_.isEqual(currentArtifact.compiler.settings, this._compilerSettings);
+ const didSourceChange = currentArtifact.sourceTreeHashHex !== sourceTreeHashHex;
+ shouldCompile = isUserOnLatestVersion || didCompilerSettingsChange || didSourceChange;
}
if (!shouldCompile) {
return;
@@ -139,30 +162,14 @@ export class Compiler {
logUtils.log(`Compiling ${contractName} with Solidity v${solcVersion}...`);
const source = contractSource.source;
- const absoluteFilePath = contractSource.path;
const standardInput: solc.StandardInput = {
language: 'Solidity',
sources: {
- [absoluteFilePath]: {
- urls: [`file://${absoluteFilePath}`],
- },
- },
- settings: {
- optimizer: {
- enabled: this._optimizerEnabled,
- },
- outputSelection: {
- '*': {
- '*': [
- 'abi',
- 'evm.bytecode.object',
- 'evm.bytecode.sourceMap',
- 'evm.deployedBytecode.object',
- 'evm.deployedBytecode.sourceMap',
- ],
- },
+ [contractSource.path]: {
+ content: contractSource.source,
},
},
+ settings: this._compilerSettings,
};
const compiled: solc.StandardOutput = JSON.parse(
solcInstance.compileStandardWrapper(JSON.stringify(standardInput), importPath => {
@@ -188,34 +195,28 @@ export class Compiler {
});
}
}
- const compiledData = compiled.contracts[absoluteFilePath][contractName];
+ const compiledData = compiled.contracts[contractSource.path][contractName];
if (_.isUndefined(compiledData)) {
throw new Error(
- `Contract ${contractName} not found in ${absoluteFilePath}. Please make sure your contract has the same name as it's file name`,
+ `Contract ${contractName} not found in ${
+ contractSource.path
+ }. Please make sure your contract has the same name as it's file name`,
);
}
- const abi: ContractAbi = compiledData.abi;
- const bytecode = `0x${compiledData.evm.bytecode.object}`;
- const runtimeBytecode = `0x${compiledData.evm.deployedBytecode.object}`;
- const sourceMap = compiledData.evm.bytecode.sourceMap;
- const sourceMapRuntime = compiledData.evm.deployedBytecode.sourceMap;
- const unresolvedSourcePaths = _.keys(compiled.sources);
- const sources = _.map(
- unresolvedSourcePaths,
- unresolvedSourcePath => this._resolver.resolve(unresolvedSourcePath).path,
+ const sourceCodes = _.mapValues(
+ compiled.sources,
+ (_1, sourceFilePath) => this._resolver.resolve(sourceFilePath).source,
);
- const updated_at = Date.now();
- const contractNetworkData: ContractNetworkData = {
- solc_version: solcVersion,
- source_tree_hash: sourceTreeHashHex,
- optimizer_enabled: this._optimizerEnabled,
- abi,
- bytecode,
- runtime_bytecode: runtimeBytecode,
- updated_at,
- source_map: sourceMap,
- source_map_runtime: sourceMapRuntime,
- sources,
+ const contractVersion: ContractVersionData = {
+ compilerOutput: compiledData,
+ sources: compiled.sources,
+ sourceCodes,
+ sourceTreeHashHex,
+ compiler: {
+ name: 'solc',
+ version: solcVersion,
+ settings: this._compilerSettings,
+ },
};
let newArtifact: ContractArtifact;
@@ -223,17 +224,14 @@ export class Compiler {
const currentArtifact = currentArtifactIfExists as ContractArtifact;
newArtifact = {
...currentArtifact,
- networks: {
- ...currentArtifact.networks,
- [this._networkId]: contractNetworkData,
- },
+ ...contractVersion,
};
} else {
newArtifact = {
- contract_name: contractName,
- networks: {
- [this._networkId]: contractNetworkData,
- },
+ schemaVersion: constants.LATEST_ARTIFACT_VERSION,
+ contractName,
+ ...contractVersion,
+ networks: {},
};
}
diff --git a/packages/deployer/src/deployer.ts b/packages/deployer/src/deployer.ts
index ad05417b1..c8c3a9a06 100644
--- a/packages/deployer/src/deployer.ts
+++ b/packages/deployer/src/deployer.ts
@@ -2,6 +2,7 @@ import { AbiType, ConstructorAbi, ContractAbi, Provider, TxData } from '@0xproje
import { logUtils } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
+import * as solc from 'solc';
import * as Web3 from 'web3';
import { Contract } from './utils/contract';
@@ -28,7 +29,20 @@ export class Deployer {
private _artifactsDir: string;
private _networkId: number;
private _defaults: Partial<TxData>;
-
+ /**
+ * Gets data for current version stored in artifact.
+ * @param contractArtifact The contract artifact.
+ * @return Version specific contract data.
+ */
+ private static _getContractCompilerOutputFromArtifactIfExists(
+ contractArtifact: ContractArtifact,
+ ): solc.StandardContractOutput {
+ const compilerOutputIfExists = contractArtifact.compilerOutput;
+ if (_.isUndefined(compilerOutputIfExists)) {
+ throw new Error(`Compiler output not found in artifact for contract: ${contractArtifact.contractName}`);
+ }
+ return compilerOutputIfExists;
+ }
/**
* Instantiate a new instance of the Deployer class.
* @param opts Deployer options, including either an RPC url or Provider instance.
@@ -58,10 +72,8 @@ export class Deployer {
*/
public async deployAsync(contractName: string, args: any[] = []): Promise<Web3.ContractInstance> {
const contractArtifactIfExists: ContractArtifact = this._loadContractArtifactIfExists(contractName);
- const contractNetworkDataIfExists: ContractNetworkData = this._getContractNetworkDataFromArtifactIfExists(
- contractArtifactIfExists,
- );
- const data = contractNetworkDataIfExists.bytecode;
+ const compilerOutput = Deployer._getContractCompilerOutputFromArtifactIfExists(contractArtifactIfExists);
+ const data = compilerOutput.evm.bytecode.object;
const from = await this._getFromAddressAsync();
const gas = await this._getAllowableGasEstimateAsync(data);
const txData = {
@@ -70,7 +82,10 @@ export class Deployer {
data,
gas,
};
- const abi = contractNetworkDataIfExists.abi;
+ if (_.isUndefined(compilerOutput.abi)) {
+ throw new Error(`ABI not found in ${contractName} artifacts`);
+ }
+ const abi = compilerOutput.abi;
const constructorAbi = _.find(abi, { type: AbiType.Constructor }) as ConstructorAbi;
const constructorArgs = _.isUndefined(constructorAbi) ? [] : constructorAbi.inputs;
if (constructorArgs.length !== args.length) {
@@ -138,15 +153,16 @@ export class Deployer {
args: any[],
): Promise<void> {
const contractArtifactIfExists: ContractArtifact = this._loadContractArtifactIfExists(contractName);
- const contractNetworkDataIfExists: ContractNetworkData = this._getContractNetworkDataFromArtifactIfExists(
- contractArtifactIfExists,
- );
- const abi = contractNetworkDataIfExists.abi;
+ const compilerOutput = Deployer._getContractCompilerOutputFromArtifactIfExists(contractArtifactIfExists);
+ if (_.isUndefined(compilerOutput.abi)) {
+ throw new Error(`ABI not found in ${contractName} artifacts`);
+ }
+ const abi = compilerOutput.abi;
const encodedConstructorArgs = encoder.encodeConstructorArgsFromAbi(args, abi);
- const newContractData = {
- ...contractNetworkDataIfExists,
+ const newContractData: ContractNetworkData = {
address: contractAddress,
- constructor_args: encodedConstructorArgs,
+ links: {},
+ constructorArgs: encodedConstructorArgs,
};
const newArtifact = {
...contractArtifactIfExists,
@@ -174,18 +190,6 @@ export class Deployer {
}
}
/**
- * Gets data for current networkId stored in artifact.
- * @param contractArtifact The contract artifact.
- * @return Network specific contract data.
- */
- private _getContractNetworkDataFromArtifactIfExists(contractArtifact: ContractArtifact): ContractNetworkData {
- const contractNetworkDataIfExists = contractArtifact.networks[this._networkId];
- if (_.isUndefined(contractNetworkDataIfExists)) {
- throw new Error(`Data not found in artifact for contract: ${contractArtifact.contract_name}`);
- }
- return contractNetworkDataIfExists;
- }
- /**
* Gets the address to use for sending a transaction.
* @return The default from address. If not specified, returns the first address accessible by web3.
*/
diff --git a/packages/deployer/src/index.ts b/packages/deployer/src/index.ts
index 186d644ef..31a75677b 100644
--- a/packages/deployer/src/index.ts
+++ b/packages/deployer/src/index.ts
@@ -1,2 +1,3 @@
export { Deployer } from './deployer';
export { Compiler } from './compiler';
+export { ContractArtifact, ContractNetworks } from './utils/types';
diff --git a/packages/deployer/src/utils/constants.ts b/packages/deployer/src/utils/constants.ts
index 6f9dfb994..df2ddb3b2 100644
--- a/packages/deployer/src/utils/constants.ts
+++ b/packages/deployer/src/utils/constants.ts
@@ -1,4 +1,5 @@
export const constants = {
SOLIDITY_FILE_EXTENSION: '.sol',
BASE_COMPILER_URL: 'https://ethereum.github.io/solc-bin/bin/',
+ LATEST_ARTIFACT_VERSION: '2.0.0',
};
diff --git a/packages/deployer/src/utils/types.ts b/packages/deployer/src/utils/types.ts
index a20d0f627..19c27df67 100644
--- a/packages/deployer/src/utils/types.ts
+++ b/packages/deployer/src/utils/types.ts
@@ -1,4 +1,5 @@
import { ContractAbi, Provider, TxData } from '@0xproject/types';
+import * as solc from 'solc';
import * as Web3 from 'web3';
import * as yargs from 'yargs';
@@ -9,28 +10,40 @@ export enum AbiType {
Fallback = 'fallback',
}
-export interface ContractArtifact {
- contract_name: string;
+export interface ContractArtifact extends ContractVersionData {
+ schemaVersion: string;
+ contractName: string;
networks: ContractNetworks;
}
+export interface ContractVersionData {
+ compiler: {
+ name: 'solc';
+ version: string;
+ settings: solc.CompilerSettings;
+ };
+ sources: {
+ [sourceName: string]: {
+ id: number;
+ };
+ };
+ sourceCodes: {
+ [sourceName: string]: string;
+ };
+ sourceTreeHashHex: string;
+ compilerOutput: solc.StandardContractOutput;
+}
+
export interface ContractNetworks {
- [key: number]: ContractNetworkData;
+ [networkId: number]: ContractNetworkData;
}
export interface ContractNetworkData {
- solc_version: string;
- optimizer_enabled: boolean;
- source_tree_hash: string;
- abi: ContractAbi;
- bytecode: string;
- runtime_bytecode: string;
- address?: string;
- constructor_args?: string;
- updated_at: number;
- source_map: string;
- source_map_runtime: string;
- sources: string[];
+ address: string;
+ links: {
+ [linkName: string]: string;
+ };
+ constructorArgs: string;
}
export interface SolcErrors {
@@ -42,7 +55,6 @@ export interface CliOptions extends yargs.Arguments {
contractsDir: string;
jsonrpcUrl: string;
networkId: number;
- shouldOptimize: boolean;
gasPrice: string;
account?: string;
contract?: string;
@@ -50,11 +62,10 @@ export interface CliOptions extends yargs.Arguments {
}
export interface CompilerOptions {
- contractsDir: string;
- networkId: number;
- optimizerEnabled: boolean;
- artifactsDir: string;
- specifiedContracts: Set<string>;
+ contractsDir?: string;
+ artifactsDir?: string;
+ compilerSettings?: solc.CompilerSettings;
+ contracts?: string[] | '*';
}
export interface BaseDeployerOptions {
diff --git a/packages/deployer/test/compiler_test.ts b/packages/deployer/test/compiler_test.ts
index bec111ffa..4c53a871a 100644
--- a/packages/deployer/test/compiler_test.ts
+++ b/packages/deployer/test/compiler_test.ts
@@ -19,9 +19,7 @@ describe('#Compiler', function() {
const compilerOpts: CompilerOptions = {
artifactsDir,
contractsDir,
- networkId: constants.networkId,
- optimizerEnabled: constants.optimizerEnabled,
- specifiedContracts: new Set(constants.specifiedContracts),
+ contracts: constants.contracts,
};
const compiler = new Compiler(compilerOpts);
beforeEach((done: DoneCallback) => {
@@ -39,9 +37,8 @@ describe('#Compiler', function() {
};
const exchangeArtifactString = await fsWrapper.readFileAsync(exchangeArtifactPath, opts);
const exchangeArtifact: ContractArtifact = JSON.parse(exchangeArtifactString);
- const exchangeContractData: ContractNetworkData = exchangeArtifact.networks[constants.networkId];
// The last 43 bytes of the binaries are metadata which may not be equivalent
- const unlinkedBinaryWithoutMetadata = exchangeContractData.bytecode.slice(0, -86);
+ const unlinkedBinaryWithoutMetadata = exchangeArtifact.compilerOutput.evm.bytecode.object.slice(0, -86);
const exchangeBinaryWithoutMetadata = exchange_binary.slice(0, -86);
expect(unlinkedBinaryWithoutMetadata).to.equal(exchangeBinaryWithoutMetadata);
});
diff --git a/packages/deployer/test/deployer_test.ts b/packages/deployer/test/deployer_test.ts
index d024b0c8c..8c92b38ca 100644
--- a/packages/deployer/test/deployer_test.ts
+++ b/packages/deployer/test/deployer_test.ts
@@ -20,9 +20,7 @@ describe('#Deployer', () => {
const compilerOpts: CompilerOptions = {
artifactsDir,
contractsDir,
- networkId: constants.networkId,
- optimizerEnabled: constants.optimizerEnabled,
- specifiedContracts: new Set(constants.specifiedContracts),
+ contracts: constants.contracts,
};
const compiler = new Compiler(compilerOpts);
const deployerOpts = {
@@ -56,8 +54,7 @@ describe('#Deployer', () => {
const exchangeContractData: ContractNetworkData = exchangeArtifact.networks[constants.networkId];
const exchangeAddress = exchangeContractInstance.address;
expect(exchangeAddress).to.not.equal(undefined);
- expect(exchangeContractData.address).to.equal(undefined);
- expect(exchangeContractData.constructor_args).to.equal(undefined);
+ expect(exchangeContractData).to.equal(undefined);
});
});
describe('#deployAndSaveAsync', () => {
@@ -72,7 +69,7 @@ describe('#Deployer', () => {
const exchangeContractData: ContractNetworkData = exchangeArtifact.networks[constants.networkId];
const exchangeAddress = exchangeContractInstance.address;
expect(exchangeAddress).to.be.equal(exchangeContractData.address);
- expect(constructor_args).to.be.equal(exchangeContractData.constructor_args);
+ expect(constructor_args).to.be.equal(exchangeContractData.constructorArgs);
});
});
});
diff --git a/packages/deployer/test/fixtures/exchange_bin.ts b/packages/deployer/test/fixtures/exchange_bin.ts
index 9fbf9bf95..914e76bf5 100644
--- a/packages/deployer/test/fixtures/exchange_bin.ts
+++ b/packages/deployer/test/fixtures/exchange_bin.ts
@@ -1,4 +1,4 @@
export const constructor_args =
'0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000008da0d80f5007ef1e431dd2127178d224e32c2ef4';
export const exchange_binary =
- '0x608060405234801561001057600080fd5b50604051604080612d998339810180604052810190808051906020019092919080519060200190929190505050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050612cca806100cf6000396000f3006080604052600436106100fc576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806314df96ee14610101578063288cdc911461015a5780632ac126221461019f578063363349be146101e4578063394c21e7146103f85780633b30ba59146104975780634f150787146104ee578063741bcc931461071b5780637e9abb50146107cf5780638163681e1461081457806398024a8b146108a6578063add1cbc5146108fb578063b7b2c7d614610952578063baa0181d14610b8b578063bc61394a14610cef578063cfc4d0ec14610dc3578063f06bbf7514610e60578063ffa1ad7414610e93575b600080fd5b34801561010d57600080fd5b50610140600480360381019080803590602001909291908035906020019092919080359060200190929190505050610f23565b604051808215151515815260200191505060405180910390f35b34801561016657600080fd5b506101896004803603810190808035600019169060200190929190505050610f7b565b6040518082815260200191505060405180910390f35b3480156101ab57600080fd5b506101ce6004803603810190808035600019169060200190929190505050610f93565b6040518082815260200191505060405180910390f35b3480156101f057600080fd5b506103e260048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561027257848483905060a00201600580602002604051908101604052809291908260056020028082843782019150505050508152602001906001019061022d565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156102f157848483905060c0020160068060200260405190810160405280929190826006602002808284378201915050505050815260200190600101906102ac565b5050505050919291929080359060200190929190803515159060200190929190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290505050610fab565b6040518082815260200191505060405180910390f35b34801561040457600080fd5b506104816004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c0019060068060200260405190810160405280929190826006602002808284378201915050505050919291929080359060200190929190505050611110565b6040518082815260200191505060405180910390f35b3480156104a357600080fd5b506104ac6115f8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156104fa57600080fd5b5061071960048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561057c57848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610537565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156105fb57848483905060c0020160068060200260405190810160405280929190826006602002808284378201915050505050815260200190600101906105b6565b505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929050505061161d565b005b34801561072757600080fd5b506107cd6004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c0019060068060200260405190810160405280929190826006602002808284378201915050505050919291929080359060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291905050506116da565b005b3480156107db57600080fd5b506107fe60048036038101908080356000191690602001909291905050506116ff565b6040518082815260200191505060405180910390f35b34801561082057600080fd5b5061088c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803560ff16906020019092919080356000191690602001909291908035600019169060200190929190505050611748565b604051808215151515815260200191505060405180910390f35b3480156108b257600080fd5b506108e5600480360381019080803590602001909291908035906020019092919080359060200190929190505050611849565b6040518082815260200191505060405180910390f35b34801561090757600080fd5b50610910611867565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561095e57600080fd5b50610b8960048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156109e057848483905060a00201600580602002604051908101604052809291908260056020028082843782019150505050508152602001906001019061099b565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610a5f57848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610a1a565b505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080351515906020019092919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929050505061188d565b005b348015610b9757600080fd5b50610ced60048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610c1957848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610bd4565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610c9857848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610c53565b505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929050505061194d565b005b348015610cfb57600080fd5b50610dad6004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c0019060068060200260405190810160405280929190826006602002808284378201915050505050919291929080359060200190929190803515159060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291905050506119c0565b6040518082815260200191505060405180910390f35b348015610dcf57600080fd5b50610e426004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c00190600680602002604051908101604052809291908260066020028082843782019150505050509192919290505050612160565b60405180826000191660001916815260200191505060405180910390f35b348015610e6c57600080fd5b50610e7561240b565b604051808261ffff1661ffff16815260200191505060405180910390f35b348015610e9f57600080fd5b50610ea8612411565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610ee8578082015181840152602081019050610ecd565b50505050905090810190601f168015610f155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600080600084801515610f3257fe5b86850991506000821415610f495760009250610f72565b610f68610f5983620f424061244a565b610f63888761244a565b61247d565b90506103e8811192505b50509392505050565b60026020528060005260406000206000915090505481565b60036020528060005260406000206000915090505481565b6000806000809150600090505b895181101561110057896000815181101515610fd057fe5b906020019060200201516003600581101515610fe857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff168a8281518110151561101157fe5b90602001906020020151600360058110151561102957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1614151561105057600080fd5b6110e4826110df8c8481518110151561106557fe5b906020019060200201518c8581518110151561107d57fe5b906020019060200201516110918d88612498565b8c8c888151811015156110a057fe5b906020019060200201518c898151811015156110b857fe5b906020019060200201518c8a8151811015156110d057fe5b906020019060200201516119c0565b6124b1565b9150878214156110f357611100565b8080600101915050610fb8565b8192505050979650505050505050565b600061111a612bd2565b6000806101606040519081016040528088600060058110151561113957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600160058110151561116857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600260058110151561119757fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860036005811015156111c657fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860046005811015156111f557fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200187600060068110151561122457fe5b6020020151815260200187600160068110151561123d57fe5b6020020151815260200187600260068110151561125657fe5b6020020151815260200187600360068110151561126f57fe5b6020020151815260200187600460068110151561128857fe5b6020020151815260200161129c8989612160565b6000191681525092503373ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff161415156112e357600080fd5b60008360a001511180156112fb575060008360c00151115b80156113075750600085115b151561131257600080fd5b8261012001514210151561136f57826101400151600019166000600381111561133757fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506115ee565b61138a8360c001516113858561014001516116ff565b612498565b915061139685836124cf565b905060008114156113f05782610140015160001916600160038111156113b857fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506115ee565b61141a600360008561014001516000191660001916815260200190815260200160002054826124b1565b60036000856101400151600019166000191681526020019081526020016000208190555082604001518360600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916836080015173ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff167f67d66f160bc93d925d05dae1794c90d2d6d6688b29b84ff069398a9b0458713186604001518760600151611552878a60c001518b60a00151611849565b878a6101400151604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200183815260200182600019166000191681526020019550505050505060405180910390a48093505b5050509392505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b86518110156116d1576116c4878281518110151561163d57fe5b90602001906020020151878381518110151561165557fe5b90602001906020020151878481518110151561166d57fe5b90602001906020020151878581518110151561168557fe5b90602001906020020151878681518110151561169d57fe5b9060200190602002015187878151811015156116b557fe5b906020019060200201516116da565b8080600101915050611623565b50505050505050565b836116eb87878760008888886119c0565b1415156116f757600080fd5b505050505050565b600061174160026000846000191660001916815260200190815260200160002054600360008560001916600019168152602001908152602001600020546124b1565b9050919050565b600060018560405180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c0182600019166000191681526020019150506040518091039020858585604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af1158015611806573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614905095945050505050565b600061185e611858858461244a565b8461247d565b90509392505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b87518110156119435761193588828151811015156118ad57fe5b9060200190602002015188838151811015156118c557fe5b9060200190602002015188848151811015156118dd57fe5b906020019060200201518888868151811015156118f657fe5b90602001906020020151888781518110151561190e57fe5b90602001906020020151888881518110151561192657fe5b906020019060200201516119c0565b508080600101915050611893565b5050505050505050565b60008090505b83518110156119ba576119ac848281518110151561196d57fe5b90602001906020020151848381518110151561198557fe5b90602001906020020151848481518110151561199d57fe5b90602001906020020151611110565b508080600101915050611953565b50505050565b60006119ca612bd2565b600080600080610160604051908101604052808e60006005811015156119ec57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6001600581101515611a1b57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6002600581101515611a4a57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6003600581101515611a7957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6004600581101515611aa857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018d6000600681101515611ad757fe5b602002015181526020018d6001600681101515611af057fe5b602002015181526020018d6002600681101515611b0957fe5b602002015181526020018d6003600681101515611b2257fe5b602002015181526020018d6004600681101515611b3b57fe5b60200201518152602001611b4f8f8f612160565b600019168152509450600073ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161480611bc657503373ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff16145b1515611bd157600080fd5b60008560a00151118015611be9575060008560c00151115b8015611bf5575060008b115b1515611c0057600080fd5b611c1685600001518661014001518b8b8b611748565b1515611c2157600080fd5b84610120015142101515611c7e578461014001516000191660006003811115611c4657fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b611c998560c00151611c948761014001516116ff565b612498565b9350611ca58b856124cf565b95506000861415611cff578461014001516000191660016003811115611cc757fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b611d12868660c001518760a00151610f23565b15611d66578461014001516000191660026003811115611d2e57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b89158015611d7b5750611d7985876124e8565b155b15611dce5784610140015160001916600380811115611d9657fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b611de1868660c001518760a00151611849565b9250611e0d600260008761014001516000191660001916815260200190815260200160002054876124b1565b600260008761014001516000191660001916815260200190815260200160002081905550611e45856040015186600001513386612838565b1515611e5057600080fd5b611e64856060015133876000015189612838565b1515611e6f57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16856080015173ffffffffffffffffffffffffffffffffffffffff16141515611f6e5760008560e001511115611f0c57611ec9868660c001518760e00151611849565b9150611f006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168660000151876080015185612838565b1515611f0b57600080fd5b5b60008561010001511115611f6d57611f2e868660c00151876101000151611849565b9050611f616000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1633876080015184612838565b1515611f6c57600080fd5b5b5b84604001518560600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916856080015173ffffffffffffffffffffffffffffffffffffffff16866000015173ffffffffffffffffffffffffffffffffffffffff167f0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb33389604001518a60600151898d8a8a8f6101400151604051808973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200184815260200183815260200182600019166000191681526020019850505050505050505060405180910390a48595505b5050505050979650505050505050565b60003083600060058110151561217257fe5b602002015184600160058110151561218657fe5b602002015185600260058110151561219a57fe5b60200201518660036005811015156121ae57fe5b60200201518760046005811015156121c257fe5b60200201518760006006811015156121d657fe5b60200201518860016006811015156121ea57fe5b60200201518960026006811015156121fe57fe5b60200201518a600360068110151561221257fe5b60200201518b600460068110151561222657fe5b60200201518c600560068110151561223a57fe5b6020020151604051808d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018781526020018681526020018581526020018481526020018381526020018281526020019c505050505050505050505050506040518091039020905092915050565b61138781565b6040805190810160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6000808284029050600084148061246b575082848281151561246857fe5b04145b151561247357fe5b8091505092915050565b600080828481151561248b57fe5b0490508091505092915050565b60008282111515156124a657fe5b818303905092915050565b60008082840190508381101515156124c557fe5b8091505092915050565b60008183106124de57816124e0565b825b905092915050565b600080600080600080600080600033975061250c8a8c60c001518d60a00151611849565b9650600073ffffffffffffffffffffffffffffffffffffffff168b6080015173ffffffffffffffffffffffffffffffffffffffff161415156127b9576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6040015173ffffffffffffffffffffffffffffffffffffffff161495506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6060015173ffffffffffffffffffffffffffffffffffffffff161494506126078a8c60c001518d60e00151611849565b935061261d8a8c60c001518d6101000151611849565b92508561262a5783612635565b61263487856124b1565b5b915084612642578261264d565b61264c8a846124b1565b5b90508161267f6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d600001516129ac565b10806126b85750816126b66000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d60000151612a94565b105b806126ec5750806126ea6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a6129ac565b105b8061272057508061271e6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a612a94565b105b1561272e576000985061282a565b8515801561276757508661274a8c604001518d600001516129ac565b10806127665750866127648c604001518d60000151612a94565b105b5b15612775576000985061282a565b841580156127a657508961278d8c606001518a6129ac565b10806127a55750896127a38c606001518a612a94565b105b5b156127b4576000985061282a565b612825565b866127cc8c604001518d600001516129ac565b10806127e85750866127e68c604001518d60000151612a94565b105b806127ff5750896127fd8c606001518a6129ac565b105b806128165750896128148c606001518a612a94565b105b15612824576000985061282a565b5b600198505b505050505050505092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166315dacbea868686866040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001945050505050602060405180830381600087803b15801561296757600080fd5b505af115801561297b573d6000803e3d6000fd5b505050506040513d602081101561299157600080fd5b81019080805190602001909291905050509050949350505050565b60008273ffffffffffffffffffffffffffffffffffffffff166370a0823161138761ffff16846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600088803b158015612a5057600080fd5b5087f1158015612a64573d6000803e3d6000fd5b50505050506040513d6020811015612a7b57600080fd5b8101908080519060200190929190505050905092915050565b60008273ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e61138761ffff1684600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600088803b158015612b8e57600080fd5b5087f1158015612ba2573d6000803e3d6000fd5b50505050506040513d6020811015612bb957600080fd5b8101908080519060200190929190505050905092915050565b61016060405190810160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000801916815250905600a165627a7a72305820f91599ebd80f85632ef190bb5e1a738e7288d68a2cf9dcc6b579d76b892dcf6f0029';
+ '608060405234801561001057600080fd5b50604051604080612d998339810180604052810190808051906020019092919080519060200190929190505050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050612cca806100cf6000396000f3006080604052600436106100fc576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806314df96ee14610101578063288cdc911461015a5780632ac126221461019f578063363349be146101e4578063394c21e7146103f85780633b30ba59146104975780634f150787146104ee578063741bcc931461071b5780637e9abb50146107cf5780638163681e1461081457806398024a8b146108a6578063add1cbc5146108fb578063b7b2c7d614610952578063baa0181d14610b8b578063bc61394a14610cef578063cfc4d0ec14610dc3578063f06bbf7514610e60578063ffa1ad7414610e93575b600080fd5b34801561010d57600080fd5b50610140600480360381019080803590602001909291908035906020019092919080359060200190929190505050610f23565b604051808215151515815260200191505060405180910390f35b34801561016657600080fd5b506101896004803603810190808035600019169060200190929190505050610f7b565b6040518082815260200191505060405180910390f35b3480156101ab57600080fd5b506101ce6004803603810190808035600019169060200190929190505050610f93565b6040518082815260200191505060405180910390f35b3480156101f057600080fd5b506103e260048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561027257848483905060a00201600580602002604051908101604052809291908260056020028082843782019150505050508152602001906001019061022d565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156102f157848483905060c0020160068060200260405190810160405280929190826006602002808284378201915050505050815260200190600101906102ac565b5050505050919291929080359060200190929190803515159060200190929190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290505050610fab565b6040518082815260200191505060405180910390f35b34801561040457600080fd5b506104816004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c0019060068060200260405190810160405280929190826006602002808284378201915050505050919291929080359060200190929190505050611110565b6040518082815260200191505060405180910390f35b3480156104a357600080fd5b506104ac6115f8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156104fa57600080fd5b5061071960048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561057c57848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610537565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156105fb57848483905060c0020160068060200260405190810160405280929190826006602002808284378201915050505050815260200190600101906105b6565b505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929050505061161d565b005b34801561072757600080fd5b506107cd6004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c0019060068060200260405190810160405280929190826006602002808284378201915050505050919291929080359060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291905050506116da565b005b3480156107db57600080fd5b506107fe60048036038101908080356000191690602001909291905050506116ff565b6040518082815260200191505060405180910390f35b34801561082057600080fd5b5061088c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803560ff16906020019092919080356000191690602001909291908035600019169060200190929190505050611748565b604051808215151515815260200191505060405180910390f35b3480156108b257600080fd5b506108e5600480360381019080803590602001909291908035906020019092919080359060200190929190505050611849565b6040518082815260200191505060405180910390f35b34801561090757600080fd5b50610910611867565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561095e57600080fd5b50610b8960048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156109e057848483905060a00201600580602002604051908101604052809291908260056020028082843782019150505050508152602001906001019061099b565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610a5f57848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610a1a565b505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080351515906020019092919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929050505061188d565b005b348015610b9757600080fd5b50610ced60048036038101908080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610c1957848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610bd4565b5050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610c9857848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610c53565b505050505091929192908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929050505061194d565b005b348015610cfb57600080fd5b50610dad6004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c0019060068060200260405190810160405280929190826006602002808284378201915050505050919291929080359060200190929190803515159060200190929190803560ff169060200190929190803560001916906020019092919080356000191690602001909291905050506119c0565b6040518082815260200191505060405180910390f35b348015610dcf57600080fd5b50610e426004803603810190808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091929192908060c00190600680602002604051908101604052809291908260066020028082843782019150505050509192919290505050612160565b60405180826000191660001916815260200191505060405180910390f35b348015610e6c57600080fd5b50610e7561240b565b604051808261ffff1661ffff16815260200191505060405180910390f35b348015610e9f57600080fd5b50610ea8612411565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610ee8578082015181840152602081019050610ecd565b50505050905090810190601f168015610f155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600080600084801515610f3257fe5b86850991506000821415610f495760009250610f72565b610f68610f5983620f424061244a565b610f63888761244a565b61247d565b90506103e8811192505b50509392505050565b60026020528060005260406000206000915090505481565b60036020528060005260406000206000915090505481565b6000806000809150600090505b895181101561110057896000815181101515610fd057fe5b906020019060200201516003600581101515610fe857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff168a8281518110151561101157fe5b90602001906020020151600360058110151561102957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1614151561105057600080fd5b6110e4826110df8c8481518110151561106557fe5b906020019060200201518c8581518110151561107d57fe5b906020019060200201516110918d88612498565b8c8c888151811015156110a057fe5b906020019060200201518c898151811015156110b857fe5b906020019060200201518c8a8151811015156110d057fe5b906020019060200201516119c0565b6124b1565b9150878214156110f357611100565b8080600101915050610fb8565b8192505050979650505050505050565b600061111a612bd2565b6000806101606040519081016040528088600060058110151561113957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600160058110151561116857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600260058110151561119757fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860036005811015156111c657fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860046005811015156111f557fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200187600060068110151561122457fe5b6020020151815260200187600160068110151561123d57fe5b6020020151815260200187600260068110151561125657fe5b6020020151815260200187600360068110151561126f57fe5b6020020151815260200187600460068110151561128857fe5b6020020151815260200161129c8989612160565b6000191681525092503373ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff161415156112e357600080fd5b60008360a001511180156112fb575060008360c00151115b80156113075750600085115b151561131257600080fd5b8261012001514210151561136f57826101400151600019166000600381111561133757fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506115ee565b61138a8360c001516113858561014001516116ff565b612498565b915061139685836124cf565b905060008114156113f05782610140015160001916600160038111156113b857fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506115ee565b61141a600360008561014001516000191660001916815260200190815260200160002054826124b1565b60036000856101400151600019166000191681526020019081526020016000208190555082604001518360600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916836080015173ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff167f67d66f160bc93d925d05dae1794c90d2d6d6688b29b84ff069398a9b0458713186604001518760600151611552878a60c001518b60a00151611849565b878a6101400151604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200183815260200182600019166000191681526020019550505050505060405180910390a48093505b5050509392505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b86518110156116d1576116c4878281518110151561163d57fe5b90602001906020020151878381518110151561165557fe5b90602001906020020151878481518110151561166d57fe5b90602001906020020151878581518110151561168557fe5b90602001906020020151878681518110151561169d57fe5b9060200190602002015187878151811015156116b557fe5b906020019060200201516116da565b8080600101915050611623565b50505050505050565b836116eb87878760008888886119c0565b1415156116f757600080fd5b505050505050565b600061174160026000846000191660001916815260200190815260200160002054600360008560001916600019168152602001908152602001600020546124b1565b9050919050565b600060018560405180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c0182600019166000191681526020019150506040518091039020858585604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af1158015611806573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614905095945050505050565b600061185e611858858461244a565b8461247d565b90509392505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b87518110156119435761193588828151811015156118ad57fe5b9060200190602002015188838151811015156118c557fe5b9060200190602002015188848151811015156118dd57fe5b906020019060200201518888868151811015156118f657fe5b90602001906020020151888781518110151561190e57fe5b90602001906020020151888881518110151561192657fe5b906020019060200201516119c0565b508080600101915050611893565b5050505050505050565b60008090505b83518110156119ba576119ac848281518110151561196d57fe5b90602001906020020151848381518110151561198557fe5b90602001906020020151848481518110151561199d57fe5b90602001906020020151611110565b508080600101915050611953565b50505050565b60006119ca612bd2565b600080600080610160604051908101604052808e60006005811015156119ec57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6001600581101515611a1b57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6002600581101515611a4a57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6003600581101515611a7957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e6004600581101515611aa857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018d6000600681101515611ad757fe5b602002015181526020018d6001600681101515611af057fe5b602002015181526020018d6002600681101515611b0957fe5b602002015181526020018d6003600681101515611b2257fe5b602002015181526020018d6004600681101515611b3b57fe5b60200201518152602001611b4f8f8f612160565b600019168152509450600073ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161480611bc657503373ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff16145b1515611bd157600080fd5b60008560a00151118015611be9575060008560c00151115b8015611bf5575060008b115b1515611c0057600080fd5b611c1685600001518661014001518b8b8b611748565b1515611c2157600080fd5b84610120015142101515611c7e578461014001516000191660006003811115611c4657fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b611c998560c00151611c948761014001516116ff565b612498565b9350611ca58b856124cf565b95506000861415611cff578461014001516000191660016003811115611cc757fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b611d12868660c001518760a00151610f23565b15611d66578461014001516000191660026003811115611d2e57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b89158015611d7b5750611d7985876124e8565b155b15611dce5784610140015160001916600380811115611d9657fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612150565b611de1868660c001518760a00151611849565b9250611e0d600260008761014001516000191660001916815260200190815260200160002054876124b1565b600260008761014001516000191660001916815260200190815260200160002081905550611e45856040015186600001513386612838565b1515611e5057600080fd5b611e64856060015133876000015189612838565b1515611e6f57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16856080015173ffffffffffffffffffffffffffffffffffffffff16141515611f6e5760008560e001511115611f0c57611ec9868660c001518760e00151611849565b9150611f006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168660000151876080015185612838565b1515611f0b57600080fd5b5b60008561010001511115611f6d57611f2e868660c00151876101000151611849565b9050611f616000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1633876080015184612838565b1515611f6c57600080fd5b5b5b84604001518560600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916856080015173ffffffffffffffffffffffffffffffffffffffff16866000015173ffffffffffffffffffffffffffffffffffffffff167f0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb33389604001518a60600151898d8a8a8f6101400151604051808973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200184815260200183815260200182600019166000191681526020019850505050505050505060405180910390a48595505b5050505050979650505050505050565b60003083600060058110151561217257fe5b602002015184600160058110151561218657fe5b602002015185600260058110151561219a57fe5b60200201518660036005811015156121ae57fe5b60200201518760046005811015156121c257fe5b60200201518760006006811015156121d657fe5b60200201518860016006811015156121ea57fe5b60200201518960026006811015156121fe57fe5b60200201518a600360068110151561221257fe5b60200201518b600460068110151561222657fe5b60200201518c600560068110151561223a57fe5b6020020151604051808d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018781526020018681526020018581526020018481526020018381526020018281526020019c505050505050505050505050506040518091039020905092915050565b61138781565b6040805190810160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6000808284029050600084148061246b575082848281151561246857fe5b04145b151561247357fe5b8091505092915050565b600080828481151561248b57fe5b0490508091505092915050565b60008282111515156124a657fe5b818303905092915050565b60008082840190508381101515156124c557fe5b8091505092915050565b60008183106124de57816124e0565b825b905092915050565b600080600080600080600080600033975061250c8a8c60c001518d60a00151611849565b9650600073ffffffffffffffffffffffffffffffffffffffff168b6080015173ffffffffffffffffffffffffffffffffffffffff161415156127b9576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6040015173ffffffffffffffffffffffffffffffffffffffff161495506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6060015173ffffffffffffffffffffffffffffffffffffffff161494506126078a8c60c001518d60e00151611849565b935061261d8a8c60c001518d6101000151611849565b92508561262a5783612635565b61263487856124b1565b5b915084612642578261264d565b61264c8a846124b1565b5b90508161267f6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d600001516129ac565b10806126b85750816126b66000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d60000151612a94565b105b806126ec5750806126ea6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a6129ac565b105b8061272057508061271e6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a612a94565b105b1561272e576000985061282a565b8515801561276757508661274a8c604001518d600001516129ac565b10806127665750866127648c604001518d60000151612a94565b105b5b15612775576000985061282a565b841580156127a657508961278d8c606001518a6129ac565b10806127a55750896127a38c606001518a612a94565b105b5b156127b4576000985061282a565b612825565b866127cc8c604001518d600001516129ac565b10806127e85750866127e68c604001518d60000151612a94565b105b806127ff5750896127fd8c606001518a6129ac565b105b806128165750896128148c606001518a612a94565b105b15612824576000985061282a565b5b600198505b505050505050505092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166315dacbea868686866040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001945050505050602060405180830381600087803b15801561296757600080fd5b505af115801561297b573d6000803e3d6000fd5b505050506040513d602081101561299157600080fd5b81019080805190602001909291905050509050949350505050565b60008273ffffffffffffffffffffffffffffffffffffffff166370a0823161138761ffff16846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600088803b158015612a5057600080fd5b5087f1158015612a64573d6000803e3d6000fd5b50505050506040513d6020811015612a7b57600080fd5b8101908080519060200190929190505050905092915050565b60008273ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e61138761ffff1684600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600088803b158015612b8e57600080fd5b5087f1158015612ba2573d6000803e3d6000fd5b50505050506040513d6020811015612bb957600080fd5b8101908080519060200190929190505050905092915050565b61016060405190810160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000801916815250905600a165627a7a72305820f91599ebd80f85632ef190bb5e1a738e7288d68a2cf9dcc6b579d76b892dcf6f0029';
diff --git a/packages/deployer/test/util/constants.ts b/packages/deployer/test/util/constants.ts
index b93081a80..88d6db550 100644
--- a/packages/deployer/test/util/constants.ts
+++ b/packages/deployer/test/util/constants.ts
@@ -7,5 +7,5 @@ export const constants = {
timeoutMs: 30000,
zrxTokenAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498',
tokenTransferProxyAddress: '0x8da0d80f5007ef1e431dd2127178d224e32c2ef4',
- specifiedContracts: '*',
+ contracts: '*' as '*',
};
diff --git a/packages/dev-utils/src/coverage.ts b/packages/dev-utils/src/coverage.ts
index 67c87ec30..743573874 100644
--- a/packages/dev-utils/src/coverage.ts
+++ b/packages/dev-utils/src/coverage.ts
@@ -13,7 +13,7 @@ export const coverage = {
return coverageSubprovider;
},
_getCoverageSubprovider(): CoverageSubprovider {
- const artifactsPath = '../migrations/src/artifacts';
+ const artifactsPath = '../migrations/artifacts/1.0.0';
const contractsPath = 'src/contracts';
const networkId = 50;
const defaultFromAddress = constants.TESTRPC_FIRST_ADDRESS;
diff --git a/packages/metacoin/compiler.json b/packages/metacoin/compiler.json
new file mode 100644
index 000000000..f5817e0c8
--- /dev/null
+++ b/packages/metacoin/compiler.json
@@ -0,0 +1,15 @@
+{
+ "compilerSettings": {
+ "outputSelection": {
+ "*": {
+ "*": [
+ "abi",
+ "evm.bytecode.object",
+ "evm.bytecode.sourceMap",
+ "evm.deployedBytecode.object",
+ "evm.deployedBytecode.sourceMap"
+ ]
+ }
+ }
+ }
+}
diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json
index 1ab749017..17aad0aaf 100644
--- a/packages/metacoin/package.json
+++ b/packages/metacoin/package.json
@@ -12,13 +12,13 @@
"build": "tsc",
"test": "run-s build run_mocha",
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
- "run_mocha": "mocha lib/test/**/*.js --bail --exit",
+ "run_mocha": "mocha lib/test/**/*_test.js lib/test/global_hooks.js --bail --exit",
"generate_contract_wrappers": "node ../abi-gen/lib/index.js --abis 'artifacts/Metacoin.json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers --backend ethers && prettier --write 'src/contract_wrappers/**.ts'",
"coverage:report:text": "istanbul report text",
"coverage:report:html": "istanbul report html && open coverage/index.html",
"coverage:report:lcov": "istanbul report lcov",
"test:circleci": "yarn test:coverage",
- "compile": "node ../deployer/lib/src/cli.js compile --contracts Metacoin --contracts-dir contracts --artifacts-dir artifacts"
+ "compile": "node ../deployer/lib/src/cli.js compile"
},
"author": "",
"license": "Apache-2.0",
diff --git a/packages/migrations/artifacts/1.0.0/.gitkeep b/packages/migrations/artifacts/1.0.0/.gitkeep
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/packages/migrations/artifacts/1.0.0/.gitkeep
diff --git a/packages/sol-cov/compiler.json b/packages/sol-cov/compiler.json
new file mode 100644
index 000000000..a6a0c6d3a
--- /dev/null
+++ b/packages/sol-cov/compiler.json
@@ -0,0 +1,18 @@
+{
+ "contracts": ["SimpleStorage"],
+ "contractsDir": "test/fixtures/contracts",
+ "artifactsDir": "test/fixtures/artifacts",
+ "compilerSettings": {
+ "outputSelection": {
+ "*": {
+ "*": [
+ "abi",
+ "evm.bytecode.object",
+ "evm.bytecode.sourceMap",
+ "evm.deployedBytecode.object",
+ "evm.deployedBytecode.sourceMap"
+ ]
+ }
+ }
+ }
+}
diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json
index 4bea117de..536d05370 100644
--- a/packages/sol-cov/package.json
+++ b/packages/sol-cov/package.json
@@ -14,7 +14,7 @@
"run_mocha": "mocha lib/test/**/*_test.js --exit",
"clean": "shx rm -rf lib scripts",
"build": "copyfiles 'test/fixtures/**/*' ./lib && tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts",
- "compile_test": "node ../deployer/lib/src/cli.js compile --contracts SimpleStorage --contracts-dir test/fixtures/contracts --artifacts-dir test/fixtures/artifacts",
+ "compile_test": "node ../deployer/lib/src/cli.js compile",
"manual:postpublish": "yarn build; node ./scripts/postpublish.js",
"docs:stage": "yarn build && node ./scripts/stage_docs.js",
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_FILES",
diff --git a/packages/sol-cov/src/collect_contract_data.ts b/packages/sol-cov/src/collect_contract_data.ts
index 1d8bc7178..bb20e98be 100644
--- a/packages/sol-cov/src/collect_contract_data.ts
+++ b/packages/sol-cov/src/collect_contract_data.ts
@@ -8,25 +8,24 @@ import { ContractData } from './types';
export const collectContractsData = (artifactsPath: string, sourcesPath: string, networkId: number) => {
const artifactsGlob = `${artifactsPath}/**/*.json`;
const artifactFileNames = glob.sync(artifactsGlob, { absolute: true });
- const contractsDataIfExists: Array<ContractData | {}> = _.map(artifactFileNames, artifactFileName => {
+ const contractsData: ContractData[] = [];
+ _.forEach(artifactFileNames, artifactFileName => {
const artifact = JSON.parse(fs.readFileSync(artifactFileName).toString());
- const sources = artifact.networks[networkId].sources;
- const contractName = artifact.contract_name;
+ const sources = _.keys(artifact.sources);
+ const contractName = artifact.contractName;
// We don't compute coverage for dependencies
- const sourceCodes = _.map(sources, (source: string) => fs.readFileSync(source).toString());
- if (_.isUndefined(artifact.networks[networkId])) {
- throw new Error(`No ${contractName} artifacts found for networkId ${networkId}`);
- }
+ const sourceCodes = _.map(sources, (source: string) =>
+ fs.readFileSync(path.join(sourcesPath, source)).toString(),
+ );
const contractData = {
sourceCodes,
sources,
- sourceMap: artifact.networks[networkId].source_map,
- sourceMapRuntime: artifact.networks[networkId].source_map_runtime,
- runtimeBytecode: artifact.networks[networkId].runtime_bytecode,
- bytecode: artifact.networks[networkId].bytecode,
+ bytecode: artifact.compilerOutput.evm.bytecode.object,
+ sourceMap: artifact.compilerOutput.evm.bytecode.sourceMap,
+ runtimeBytecode: artifact.compilerOutput.evm.deployedBytecode.object,
+ sourceMapRuntime: artifact.compilerOutput.evm.deployedBytecode.sourceMap,
};
- return contractData;
+ contractsData.push(contractData);
});
- const contractsData = _.filter(contractsDataIfExists, contractData => !_.isEmpty(contractData)) as ContractData[];
return contractsData;
};
diff --git a/packages/sol-cov/src/coverage_manager.ts b/packages/sol-cov/src/coverage_manager.ts
index 230ccc3c9..6a57d07c9 100644
--- a/packages/sol-cov/src/coverage_manager.ts
+++ b/packages/sol-cov/src/coverage_manager.ts
@@ -29,10 +29,31 @@ import {
import { utils } from './utils';
export class CoverageManager {
+ private _sourcesPath: string;
private _traceInfos: TraceInfo[] = [];
private _contractsData: ContractData[] = [];
private _getContractCodeAsync: (address: string) => Promise<string>;
- private static _getSingleFileCoverageForTrace(
+ constructor(
+ artifactsPath: string,
+ sourcesPath: string,
+ networkId: number,
+ getContractCodeAsync: (address: string) => Promise<string>,
+ ) {
+ this._getContractCodeAsync = getContractCodeAsync;
+ this._sourcesPath = sourcesPath;
+ this._contractsData = collectContractsData(artifactsPath, this._sourcesPath, networkId);
+ }
+ public appendTraceInfo(traceInfo: TraceInfo): void {
+ this._traceInfos.push(traceInfo);
+ }
+ public async writeCoverageAsync(): Promise<void> {
+ const finalCoverage = await this._computeCoverageAsync();
+ const jsonReplacer: null = null;
+ const numberOfJsonSpaces = 4;
+ const stringifiedCoverage = JSON.stringify(finalCoverage, jsonReplacer, numberOfJsonSpaces);
+ fs.writeFileSync('coverage/coverage.json', stringifiedCoverage);
+ }
+ private _getSingleFileCoverageForTrace(
contractData: ContractData,
coveredPcs: number[],
pcToSourceRange: { [programCounter: number]: SourceRange },
@@ -94,11 +115,12 @@ export class CoverageManager {
);
statementCoverage[modifierStatementId] = isModifierCovered;
}
+ const absoluteFileName = path.join(this._sourcesPath, fileName);
const partialCoverage = {
- [contractData.sources[fileIndex]]: {
+ [absoluteFileName]: {
...coverageEntriesDescription,
l: {}, // It's able to derive it from statement coverage
- path: fileName,
+ path: absoluteFileName,
f: functionCoverage,
s: statementCoverage,
b: branchCoverage,
@@ -106,31 +128,13 @@ export class CoverageManager {
};
return partialCoverage;
}
- constructor(
- artifactsPath: string,
- sourcesPath: string,
- networkId: number,
- getContractCodeAsync: (address: string) => Promise<string>,
- ) {
- this._getContractCodeAsync = getContractCodeAsync;
- this._contractsData = collectContractsData(artifactsPath, sourcesPath, networkId);
- }
- public appendTraceInfo(traceInfo: TraceInfo): void {
- this._traceInfos.push(traceInfo);
- }
- public async writeCoverageAsync(): Promise<void> {
- const finalCoverage = await this._computeCoverageAsync();
- const jsonReplacer: null = null;
- const numberOfJsonSpaces = 4;
- const stringifiedCoverage = JSON.stringify(finalCoverage, jsonReplacer, numberOfJsonSpaces);
- fs.writeFileSync('coverage/coverage.json', stringifiedCoverage);
- }
private async _computeCoverageAsync(): Promise<Coverage> {
const collector = new Collector();
for (const traceInfo of this._traceInfos) {
if (traceInfo.address !== constants.NEW_CONTRACT) {
// Runtime transaction
- const runtimeBytecode = (traceInfo as TraceInfoExistingContract).runtimeBytecode;
+ let runtimeBytecode = (traceInfo as TraceInfoExistingContract).runtimeBytecode;
+ runtimeBytecode = utils.removeHexPrefix(runtimeBytecode);
const contractData = _.find(this._contractsData, { runtimeBytecode }) as ContractData;
if (_.isUndefined(contractData)) {
throw new Error(`Transaction to an unknown address: ${traceInfo.address}`);
@@ -144,7 +148,7 @@ export class CoverageManager {
contractData.sources,
);
for (let fileIndex = 0; fileIndex < contractData.sources.length; fileIndex++) {
- const singleFileCoverageForTrace = CoverageManager._getSingleFileCoverageForTrace(
+ const singleFileCoverageForTrace = this._getSingleFileCoverageForTrace(
contractData,
traceInfo.coveredPcs,
pcToSourceRange,
@@ -154,7 +158,8 @@ export class CoverageManager {
}
} else {
// Contract creation transaction
- const bytecode = (traceInfo as TraceInfoNewContract).bytecode;
+ let bytecode = (traceInfo as TraceInfoNewContract).bytecode;
+ bytecode = utils.removeHexPrefix(bytecode);
const contractData = _.find(this._contractsData, contractDataCandidate =>
bytecode.startsWith(contractDataCandidate.bytecode),
) as ContractData;
@@ -170,7 +175,7 @@ export class CoverageManager {
contractData.sources,
);
for (let fileIndex = 0; fileIndex < contractData.sources.length; fileIndex++) {
- const singleFileCoverageForTrace = CoverageManager._getSingleFileCoverageForTrace(
+ const singleFileCoverageForTrace = this._getSingleFileCoverageForTrace(
contractData,
traceInfo.coveredPcs,
pcToSourceRange,
diff --git a/packages/sol-cov/src/utils.ts b/packages/sol-cov/src/utils.ts
index f155043a1..d970c42ee 100644
--- a/packages/sol-cov/src/utils.ts
+++ b/packages/sol-cov/src/utils.ts
@@ -4,6 +4,10 @@ export const utils = {
compareLineColumn(lhs: LineColumn, rhs: LineColumn): number {
return lhs.line !== rhs.line ? lhs.line - rhs.line : lhs.column - rhs.column;
},
+ removeHexPrefix(hex: string): string {
+ const hexPrefix = '0x';
+ return hex.startsWith(hexPrefix) ? hex.slice(hexPrefix.length) : hex;
+ },
isRangeInside(childRange: SingleFileSourceRange, parentRange: SingleFileSourceRange): boolean {
return (
utils.compareLineColumn(parentRange.start, childRange.start) <= 0 &&
diff --git a/packages/sol-resolver/src/index.ts b/packages/sol-resolver/src/index.ts
index cd6ec42ec..a86053259 100644
--- a/packages/sol-resolver/src/index.ts
+++ b/packages/sol-resolver/src/index.ts
@@ -3,6 +3,7 @@ export { FallthroughResolver } from './resolvers/fallthrough_resolver';
export { URLResolver } from './resolvers/url_resolver';
export { NPMResolver } from './resolvers/npm_resolver';
export { FSResolver } from './resolvers/fs_resolver';
+export { RelativeFSResolver } from './resolvers/relative_fs_resolver';
export { NameResolver } from './resolvers/name_resolver';
export { EnumerableResolver } from './resolvers/enumerable_resolver';
export { Resolver } from './resolvers/resolver';
diff --git a/packages/sol-resolver/src/resolvers/name_resolver.ts b/packages/sol-resolver/src/resolvers/name_resolver.ts
index 6849b7610..76bed802e 100644
--- a/packages/sol-resolver/src/resolvers/name_resolver.ts
+++ b/packages/sol-resolver/src/resolvers/name_resolver.ts
@@ -18,7 +18,8 @@ export class NameResolver extends EnumerableResolver {
const onFile = (filePath: string) => {
const contractName = path.basename(filePath, SOLIDITY_FILE_EXTENSION);
if (contractName === lookupContractName) {
- const source = fs.readFileSync(filePath).toString();
+ const absoluteContractPath = path.join(this._contractsDir, filePath);
+ const source = fs.readFileSync(absoluteContractPath).toString();
contractSource = {
source,
path: filePath,
@@ -35,7 +36,8 @@ export class NameResolver extends EnumerableResolver {
const contractSources: ContractSource[] = [];
const onFile = (filePath: string) => {
const contractName = path.basename(filePath, SOLIDITY_FILE_EXTENSION);
- const source = fs.readFileSync(filePath).toString();
+ const absoluteContractPath = path.join(this._contractsDir, filePath);
+ const source = fs.readFileSync(absoluteContractPath).toString();
const contractSource = {
source,
path: filePath,
@@ -54,9 +56,10 @@ export class NameResolver extends EnumerableResolver {
throw new Error(`No directory found at ${dirPath}`);
}
for (const fileName of dirContents) {
- const entryPath = path.join(dirPath, fileName);
- const isDirectory = fs.lstatSync(entryPath).isDirectory();
- const isComplete = isDirectory ? this._traverseContractsDir(entryPath, onFile) : onFile(entryPath);
+ const absoluteEntryPath = path.join(dirPath, fileName);
+ const isDirectory = fs.lstatSync(absoluteEntryPath).isDirectory();
+ const entryPath = path.relative(this._contractsDir, absoluteEntryPath);
+ const isComplete = isDirectory ? this._traverseContractsDir(absoluteEntryPath, onFile) : onFile(entryPath);
if (isComplete) {
return isComplete;
}
diff --git a/packages/sol-resolver/src/resolvers/relative_fs_resolver.ts b/packages/sol-resolver/src/resolvers/relative_fs_resolver.ts
new file mode 100644
index 000000000..2317ede83
--- /dev/null
+++ b/packages/sol-resolver/src/resolvers/relative_fs_resolver.ts
@@ -0,0 +1,26 @@
+import * as fs from 'fs';
+import * as path from 'path';
+
+import { ContractSource } from '../types';
+
+import { Resolver } from './resolver';
+
+export class RelativeFSResolver extends Resolver {
+ private _contractsDir: string;
+ constructor(contractsDir: string) {
+ super();
+ this._contractsDir = contractsDir;
+ }
+ // tslint:disable-next-line:prefer-function-over-method
+ public resolveIfExists(importPath: string): ContractSource | undefined {
+ const filePath = path.join(this._contractsDir, importPath);
+ if (fs.existsSync(filePath)) {
+ const fileContent = fs.readFileSync(filePath).toString();
+ return {
+ source: fileContent,
+ path: importPath,
+ };
+ }
+ return undefined;
+ }
+}
diff --git a/packages/typescript-typings/types/solc/index.d.ts b/packages/typescript-typings/types/solc/index.d.ts
index b20f9b2ff..5a87ac267 100644
--- a/packages/typescript-typings/types/solc/index.d.ts
+++ b/packages/typescript-typings/types/solc/index.d.ts
@@ -59,32 +59,33 @@ declare module 'solc' {
| 'evm.gasEstimates'
| 'ewasm.wast'
| 'ewasm.wasm';
+ export interface CompilerSettings {
+ remappings?: string[];
+ optimizer?: {
+ enabled: boolean;
+ runs?: number;
+ };
+ evmVersion?: 'homestead' | 'tangerineWhistle' | 'spuriousDragon' | 'byzantium' | 'constantinople';
+ metadata?: {
+ useLiteralContent: true;
+ };
+ libraries?: {
+ [fileName: string]: {
+ [libName: string]: string;
+ };
+ };
+ outputSelection: {
+ [fileName: string]: {
+ [contractName: string]: OutputField[];
+ };
+ };
+ }
export interface StandardInput {
language: 'Solidity' | 'serpent' | 'lll' | 'assembly';
sources: {
[fileName: string]: Source;
};
- settings: {
- remappings?: string[];
- optimizer?: {
- enabled: boolean;
- runs?: number;
- };
- evmVersion?: 'homestead' | 'tangerineWhistle' | 'spuriousDragon' | 'byzantium' | 'constantinople';
- metadata?: {
- useLiteralContent: true;
- };
- libraries?: {
- [fileName: string]: {
- [libName: string]: string;
- };
- };
- outputSelection: {
- [fileName: string]: {
- [contractName: string]: OutputField[];
- };
- };
- };
+ settings: CompilerSettings;
}
export type ErrorType =
| 'JSONError'
@@ -114,6 +115,19 @@ declare module 'solc' {
formattedMessage?: string;
}
import { ContractAbi } from '@0xproject/types';
+ export interface StandardContractOutput {
+ abi: ContractAbi;
+ evm: {
+ bytecode: {
+ object: string;
+ sourceMap: string;
+ };
+ deployedBytecode: {
+ object: string;
+ sourceMap: string;
+ };
+ };
+ }
export interface StandardOutput {
errors: Error[];
sources: {
@@ -125,19 +139,7 @@ declare module 'solc' {
};
contracts: {
[fileName: string]: {
- [contractName: string]: {
- abi: ContractAbi;
- evm: {
- bytecode: {
- object: string;
- sourceMap: string;
- };
- deployedBytecode: {
- object: string;
- sourceMap: string;
- };
- };
- };
+ [contractName: string]: StandardContractOutput;
};
};
}
diff --git a/packages/website/public/images/landing/project_logos/the_ocean.png b/packages/website/public/images/landing/project_logos/the_ocean.png
index 74678b5d4..0677abc29 100644
--- a/packages/website/public/images/landing/project_logos/the_ocean.png
+++ b/packages/website/public/images/landing/project_logos/the_ocean.png
Binary files differ
diff --git a/packages/website/ts/components/legacy_portal/legacy_portal.tsx b/packages/website/ts/components/legacy_portal/legacy_portal.tsx
index 8942e4356..c45b20365 100644
--- a/packages/website/ts/components/legacy_portal/legacy_portal.tsx
+++ b/packages/website/ts/components/legacy_portal/legacy_portal.tsx
@@ -154,7 +154,6 @@ export class LegacyPortal extends React.Component<LegacyPortalProps, LegacyPorta
const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind(
this.props.dispatcher,
);
- const isDevelopment = configs.ENVIRONMENT === Environments.DEVELOPMENT;
const portalStyle: React.CSSProperties = {
minHeight: '100vh',
display: 'flex',
@@ -204,18 +203,6 @@ export class LegacyPortal extends React.Component<LegacyPortalProps, LegacyPorta
<div className="py2" style={{ backgroundColor: colors.grey50 }}>
{this.props.blockchainIsLoaded ? (
<Switch>
- {isDevelopment && (
- <Route
- path={`${WebsitePaths.Portal}/wallet`}
- render={this._renderWallet.bind(this)}
- />
- )}
- {isDevelopment && (
- <Route
- path={`${WebsitePaths.Portal}/relayers`}
- render={this._renderRelayers.bind(this)}
- />
- )}
<Route
path={`${WebsitePaths.Portal}/weth`}
render={this._renderEthWrapper.bind(this)}
@@ -294,40 +281,6 @@ export class LegacyPortal extends React.Component<LegacyPortalProps, LegacyPorta
isLedgerDialogOpen: !this.state.isLedgerDialogOpen,
});
}
- private _renderWallet() {
- const allTokens = _.values(this.props.tokenByAddress);
- const trackedTokens = _.filter(allTokens, t => t.isTracked);
- return (
- <div className="flex flex-center">
- <div className="mx-auto">
- <Wallet
- userAddress={this.props.userAddress}
- networkId={this.props.networkId}
- blockchain={this._blockchain}
- blockchainIsLoaded={this.props.blockchainIsLoaded}
- blockchainErr={this.props.blockchainErr}
- dispatcher={this.props.dispatcher}
- tokenByAddress={this.props.tokenByAddress}
- trackedTokens={trackedTokens}
- userEtherBalanceInWei={this.props.userEtherBalanceInWei}
- lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
- injectedProviderName={this.props.injectedProviderName}
- providerType={this.props.providerType}
- onToggleLedgerDialog={this.onToggleLedgerDialog.bind(this)}
- />
- </div>
- </div>
- );
- }
- private _renderRelayers() {
- return (
- <div className="flex flex-center">
- <div className="mx-auto" style={{ width: 800 }}>
- <RelayerIndex networkId={this.props.networkId} />
- </div>
- </div>
- );
- }
private _renderEthWrapper() {
return (
<EthWrappers
diff --git a/packages/website/ts/components/legacy_portal/legacy_portal_menu.tsx b/packages/website/ts/components/legacy_portal/legacy_portal_menu.tsx
index 634d966ed..94113f066 100644
--- a/packages/website/ts/components/legacy_portal/legacy_portal_menu.tsx
+++ b/packages/website/ts/components/legacy_portal/legacy_portal_menu.tsx
@@ -58,26 +58,6 @@ export class LegacyPortalMenu extends React.Component<LegacyPortalMenuProps, Leg
>
{this._renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')}
</MenuItem>
- {configs.ENVIRONMENT === Environments.DEVELOPMENT && (
- <div>
- <MenuItem
- style={this.props.menuItemStyle}
- className="py2"
- to={`${WebsitePaths.Portal}/wallet`}
- onClick={this.props.onClick.bind(this)}
- >
- {this._renderMenuItemWithIcon('Wallet', 'zmdi-balance-wallet')}
- </MenuItem>
- <MenuItem
- style={this.props.menuItemStyle}
- className="py2"
- to={`${WebsitePaths.Portal}/relayers`}
- onClick={this.props.onClick.bind(this)}
- >
- {this._renderMenuItemWithIcon('Relayers', 'zmdi-input-antenna')}
- </MenuItem>
- </div>
- )}
</div>
);
}
diff --git a/packages/website/ts/components/portal/portal.tsx b/packages/website/ts/components/portal/portal.tsx
new file mode 100644
index 000000000..b5e8150c4
--- /dev/null
+++ b/packages/website/ts/components/portal/portal.tsx
@@ -0,0 +1,263 @@
+import { colors, Styles } from '@0xproject/react-shared';
+import { BigNumber } from '@0xproject/utils';
+import * as _ from 'lodash';
+import * as React from 'react';
+import * as DocumentTitle from 'react-document-title';
+
+import { Blockchain } from 'ts/blockchain';
+import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog';
+import { LedgerConfigDialog } from 'ts/components/dialogs/ledger_config_dialog';
+import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog';
+import { AssetPicker } from 'ts/components/generate_order/asset_picker';
+import { RelayerIndex } from 'ts/components/relayer_index/relayer_index';
+import { TopBar, TopBarDisplayType } from 'ts/components/top_bar/top_bar';
+import { FlashMessage } from 'ts/components/ui/flash_message';
+import { Wallet } from 'ts/components/wallet/wallet';
+import { localStorage } from 'ts/local_storage/local_storage';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, TokenByAddress, TokenVisibility } from 'ts/types';
+import { constants } from 'ts/utils/constants';
+import { Translate } from 'ts/utils/translate';
+import { utils } from 'ts/utils/utils';
+
+export interface PortalProps {
+ blockchainErr: BlockchainErrs;
+ blockchainIsLoaded: boolean;
+ dispatcher: Dispatcher;
+ hashData: HashData;
+ injectedProviderName: string;
+ networkId: number;
+ nodeVersion: string;
+ orderFillAmount: BigNumber;
+ providerType: ProviderType;
+ screenWidth: ScreenWidths;
+ tokenByAddress: TokenByAddress;
+ userEtherBalanceInWei: BigNumber;
+ userAddress: string;
+ shouldBlockchainErrDialogBeOpen: boolean;
+ userSuppliedOrderCache: Order;
+ location: Location;
+ flashMessage?: string | React.ReactNode;
+ lastForceTokenStateRefetch: number;
+ translate: Translate;
+}
+
+interface PortalState {
+ prevNetworkId: number;
+ prevNodeVersion: string;
+ prevUserAddress: string;
+ prevPathname: string;
+ isDisclaimerDialogOpen: boolean;
+ isLedgerDialogOpen: boolean;
+ isAssetPickerDialogOpen: boolean;
+}
+
+const THROTTLE_TIMEOUT = 100;
+const TOP_BAR_HEIGHT = TopBar.heightForDisplayType(TopBarDisplayType.Expanded);
+
+const styles: Styles = {
+ root: {
+ width: '100%',
+ height: '100%',
+ backgroundColor: colors.lightestGrey,
+ },
+ body: {
+ height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`,
+ },
+ scrollContainer: {
+ height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`,
+ WebkitOverflowScrolling: 'touch',
+ overflow: 'auto',
+ },
+ title: {
+ fontWeight: 'bold',
+ fontSize: 20,
+ },
+};
+
+export class Portal extends React.Component<PortalProps, PortalState> {
+ private _blockchain: Blockchain;
+ private _throttledScreenWidthUpdate: () => void;
+ constructor(props: PortalProps) {
+ super(props);
+ this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT);
+ const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER);
+ const hasAcceptedDisclaimer =
+ !_.isUndefined(didAcceptPortalDisclaimer) && !_.isEmpty(didAcceptPortalDisclaimer);
+ this.state = {
+ prevNetworkId: this.props.networkId,
+ prevNodeVersion: this.props.nodeVersion,
+ prevUserAddress: this.props.userAddress,
+ prevPathname: this.props.location.pathname,
+ isDisclaimerDialogOpen: !hasAcceptedDisclaimer,
+ isAssetPickerDialogOpen: false,
+ isLedgerDialogOpen: false,
+ };
+ }
+ public componentDidMount() {
+ window.addEventListener('resize', this._throttledScreenWidthUpdate);
+ window.scrollTo(0, 0);
+ }
+ public componentWillMount() {
+ this._blockchain = new Blockchain(this.props.dispatcher);
+ }
+ public componentWillUnmount() {
+ this._blockchain.destroy();
+ window.removeEventListener('resize', this._throttledScreenWidthUpdate);
+ // We re-set the entire redux state when the portal is unmounted so that when it is re-rendered
+ // the initialization process always occurs from the same base state. This helps avoid
+ // initialization inconsistencies (i.e While the portal was unrendered, the user might have
+ // become disconnected from their backing Ethereum node, changed user accounts, etc...)
+ this.props.dispatcher.resetState();
+ }
+ public componentWillReceiveProps(nextProps: PortalProps) {
+ if (nextProps.networkId !== this.state.prevNetworkId) {
+ // tslint:disable-next-line:no-floating-promises
+ this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId);
+ this.setState({
+ prevNetworkId: nextProps.networkId,
+ });
+ }
+ if (nextProps.userAddress !== this.state.prevUserAddress) {
+ const newUserAddress = _.isEmpty(nextProps.userAddress) ? undefined : nextProps.userAddress;
+ // tslint:disable-next-line:no-floating-promises
+ this._blockchain.userAddressUpdatedFireAndForgetAsync(newUserAddress);
+ this.setState({
+ prevUserAddress: nextProps.userAddress,
+ });
+ }
+ if (nextProps.nodeVersion !== this.state.prevNodeVersion) {
+ // tslint:disable-next-line:no-floating-promises
+ this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion);
+ }
+ if (nextProps.location.pathname !== this.state.prevPathname) {
+ this.setState({
+ prevPathname: nextProps.location.pathname,
+ });
+ }
+ }
+ public render() {
+ const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind(
+ this.props.dispatcher,
+ );
+ const allTokens = _.values(this.props.tokenByAddress);
+ const trackedTokens = _.filter(allTokens, t => t.isTracked);
+ return (
+ <div style={styles.root}>
+ <DocumentTitle title="0x Portal DApp" />
+ <TopBar
+ userAddress={this.props.userAddress}
+ networkId={this.props.networkId}
+ injectedProviderName={this.props.injectedProviderName}
+ onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)}
+ dispatcher={this.props.dispatcher}
+ providerType={this.props.providerType}
+ blockchainIsLoaded={this.props.blockchainIsLoaded}
+ location={this.props.location}
+ blockchain={this._blockchain}
+ translate={this.props.translate}
+ displayType={TopBarDisplayType.Expanded}
+ style={{ backgroundColor: colors.lightestGrey }}
+ />
+ <div id="portal" style={styles.body}>
+ <div className="sm-flex flex-center">
+ <div className="flex-last px3">
+ <div className="py3" style={styles.title}>
+ Your Account
+ </div>
+ <Wallet
+ userAddress={this.props.userAddress}
+ networkId={this.props.networkId}
+ blockchain={this._blockchain}
+ blockchainIsLoaded={this.props.blockchainIsLoaded}
+ blockchainErr={this.props.blockchainErr}
+ dispatcher={this.props.dispatcher}
+ tokenByAddress={this.props.tokenByAddress}
+ trackedTokens={trackedTokens}
+ userEtherBalanceInWei={this.props.userEtherBalanceInWei}
+ lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
+ injectedProviderName={this.props.injectedProviderName}
+ providerType={this.props.providerType}
+ onToggleLedgerDialog={this._onToggleLedgerDialog.bind(this)}
+ onAddToken={this._onAddToken.bind(this)}
+ />
+ </div>
+ <div className="flex-auto px3" style={styles.scrollContainer}>
+ <div className="py3" style={styles.title}>
+ Explore 0x Ecosystem
+ </div>
+ <RelayerIndex networkId={this.props.networkId} />
+ </div>
+ </div>
+ <BlockchainErrDialog
+ blockchain={this._blockchain}
+ blockchainErr={this.props.blockchainErr}
+ isOpen={this.props.shouldBlockchainErrDialogBeOpen}
+ userAddress={this.props.userAddress}
+ toggleDialogFn={updateShouldBlockchainErrDialogBeOpen}
+ networkId={this.props.networkId}
+ />
+ <PortalDisclaimerDialog
+ isOpen={this.state.isDisclaimerDialogOpen}
+ onToggleDialog={this._onPortalDisclaimerAccepted.bind(this)}
+ />
+ <FlashMessage dispatcher={this.props.dispatcher} flashMessage={this.props.flashMessage} />
+ {this.props.blockchainIsLoaded && (
+ <LedgerConfigDialog
+ providerType={this.props.providerType}
+ networkId={this.props.networkId}
+ blockchain={this._blockchain}
+ dispatcher={this.props.dispatcher}
+ toggleDialogFn={this._onToggleLedgerDialog.bind(this)}
+ isOpen={this.state.isLedgerDialogOpen}
+ />
+ )}
+ <AssetPicker
+ userAddress={this.props.userAddress}
+ networkId={this.props.networkId}
+ blockchain={this._blockchain}
+ dispatcher={this.props.dispatcher}
+ isOpen={this.state.isAssetPickerDialogOpen}
+ currentTokenAddress={''}
+ onTokenChosen={this._onTokenChosen.bind(this)}
+ tokenByAddress={this.props.tokenByAddress}
+ tokenVisibility={TokenVisibility.UNTRACKED}
+ />
+ </div>
+ </div>
+ );
+ }
+ private _onTokenChosen(tokenAddress: string) {
+ if (_.isEmpty(tokenAddress)) {
+ this.setState({
+ isAssetPickerDialogOpen: false,
+ });
+ return;
+ }
+ const token = this.props.tokenByAddress[tokenAddress];
+ this.props.dispatcher.updateTokenByAddress([token]);
+ this.setState({
+ isAssetPickerDialogOpen: false,
+ });
+ }
+ private _onToggleLedgerDialog() {
+ this.setState({
+ isLedgerDialogOpen: !this.state.isLedgerDialogOpen,
+ });
+ }
+ private _onAddToken() {
+ this.setState({
+ isAssetPickerDialogOpen: !this.state.isAssetPickerDialogOpen,
+ });
+ }
+ private _onPortalDisclaimerAccepted() {
+ localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set');
+ this.setState({
+ isDisclaimerDialogOpen: false,
+ });
+ }
+ private _updateScreenWidth() {
+ const newScreenWidth = utils.getScreenWidth();
+ this.props.dispatcher.updateScreenWidth(newScreenWidth);
+ }
+}
diff --git a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
index 0b9b8165e..d88a59d15 100644
--- a/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_grid_tile.tsx
@@ -12,37 +12,6 @@ export interface RelayerGridTileProps {
networkId: number;
}
-// TODO: Get top tokens from remote
-const topTokens = [
- {
- address: '0x1dad4783cf3fe3085c1426157ab175a6119a04ba',
- decimals: 18,
- iconUrl: '/images/token_icons/makerdao.png',
- isRegistered: true,
- isTracked: true,
- name: 'Maker DAO',
- symbol: 'MKR',
- },
- {
- address: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
- decimals: 18,
- iconUrl: '/images/token_icons/melon.png',
- isRegistered: true,
- isTracked: true,
- name: 'Melon Token',
- symbol: 'MLN',
- },
- {
- address: '0xb18845c260f680d5b9d84649638813e342e4f8c9',
- decimals: 18,
- iconUrl: '/images/token_icons/augur.png',
- isRegistered: true,
- isTracked: true,
- name: 'Augur Reputation Token',
- symbol: 'REP',
- },
-];
-
const styles: Styles = {
root: {
backgroundColor: colors.white,
@@ -93,28 +62,63 @@ const styles: Styles = {
},
};
+const FALLBACK_IMG_SRC = '/images/landing/hero_chip_image.png';
+
export const RelayerGridTile: React.StatelessComponent<RelayerGridTileProps> = (props: RelayerGridTileProps) => {
const link = props.relayerInfo.appUrl || props.relayerInfo.url;
return (
- <a href={link} target="_blank" style={{ textDecoration: 'none' }}>
- <GridTile style={styles.root}>
- <div style={styles.innerDiv}>
- <img src={props.relayerInfo.headerImgUrl} style={styles.header} />
- <div style={styles.body}>
- <div className="py1" style={styles.relayerNameLabel}>
- {props.relayerInfo.name}
- </div>
- <div style={styles.dailyTradeVolumeLabel}>{props.relayerInfo.dailyTxnVolume}</div>
- <div className="py1" style={styles.subLabel}>
- Daily Trade Volume
- </div>
- <TopTokens tokens={topTokens} networkId={props.networkId} />
- <div className="py1" style={styles.subLabel}>
- Top tokens
- </div>
+ <GridTile style={styles.root}>
+ <div style={styles.innerDiv}>
+ <a href={link} target="_blank" style={{ textDecoration: 'none' }}>
+ <ImgWithFallback
+ src={props.relayerInfo.headerImgUrl}
+ fallbackSrc={FALLBACK_IMG_SRC}
+ style={styles.header}
+ />
+ </a>
+ <div style={styles.body}>
+ <div className="py1" style={styles.relayerNameLabel}>
+ {props.relayerInfo.name}
+ </div>
+ <div style={styles.dailyTradeVolumeLabel}>{props.relayerInfo.dailyTxnVolume}</div>
+ <div className="py1" style={styles.subLabel}>
+ Daily Trade Volume
+ </div>
+ <TopTokens tokens={props.relayerInfo.topTokens} networkId={props.networkId} />
+ <div className="py1" style={styles.subLabel}>
+ Top tokens
</div>
</div>
- </GridTile>
- </a>
+ </div>
+ </GridTile>
);
};
+
+interface ImgWithFallbackProps {
+ src?: string;
+ fallbackSrc: string;
+ style: React.CSSProperties;
+}
+interface ImgWithFallbackState {
+ imageLoadFailed: boolean;
+}
+class ImgWithFallback extends React.Component<ImgWithFallbackProps, ImgWithFallbackState> {
+ constructor(props: ImgWithFallbackProps) {
+ super(props);
+ this.state = {
+ imageLoadFailed: false,
+ };
+ }
+ public render() {
+ if (this.state.imageLoadFailed || _.isUndefined(this.props.src)) {
+ return <img src={this.props.fallbackSrc} style={this.props.style} />;
+ } else {
+ return <img src={this.props.src} onError={this._onError.bind(this)} style={this.props.style} />;
+ }
+ }
+ private _onError() {
+ this.setState({
+ imageLoadFailed: true,
+ });
+ }
+}
diff --git a/packages/website/ts/components/relayer_index/relayer_index.tsx b/packages/website/ts/components/relayer_index/relayer_index.tsx
index c1ab4227a..dffd0f83f 100644
--- a/packages/website/ts/components/relayer_index/relayer_index.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_index.tsx
@@ -1,5 +1,7 @@
import { colors, Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
+import CircularProgress from 'material-ui/CircularProgress';
+import FlatButton from 'material-ui/FlatButton';
import { GridList } from 'material-ui/GridList';
import * as React from 'react';
@@ -32,9 +34,9 @@ const styles: Styles = {
},
};
-const CELL_HEIGHT = 260;
+const CELL_HEIGHT = 290;
const NUMBER_OF_COLUMNS = 4;
-const GRID_PADDING = 16;
+const GRID_PADDING = 20;
export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerIndexState> {
private _isUnmounted: boolean;
@@ -55,7 +57,24 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
}
public render() {
const readyToRender = _.isUndefined(this.state.error) && !_.isUndefined(this.state.relayerInfos);
- if (readyToRender) {
+ if (!readyToRender) {
+ return (
+ <div className="col col-12" style={{ ...styles.root, height: '100%' }}>
+ <div
+ className="relative sm-px2 sm-pt2 sm-m1"
+ style={{ height: 122, top: '33%', transform: 'translateY(-50%)' }}
+ >
+ <div className="center pb2">
+ {_.isUndefined(this.state.error) ? (
+ <CircularProgress size={40} thickness={5} />
+ ) : (
+ <Retry onRetry={this._fetchRelayerInfosAsync.bind(this)} />
+ )}
+ </div>
+ </div>
+ </div>
+ );
+ } else {
return (
<div style={styles.root}>
<GridList
@@ -64,23 +83,22 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
padding={GRID_PADDING}
style={styles.gridList}
>
- {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo) => (
- <RelayerGridTile
- key={relayerInfo.name}
- relayerInfo={relayerInfo}
- networkId={this.props.networkId}
- />
+ {this.state.relayerInfos.map((relayerInfo: WebsiteBackendRelayerInfo, index) => (
+ <RelayerGridTile key={index} relayerInfo={relayerInfo} networkId={this.props.networkId} />
))}
</GridList>
</div>
);
- } else {
- // TODO: loading and error states with a scrolling container
- return null;
}
}
private async _fetchRelayerInfosAsync(): Promise<void> {
try {
+ if (!this._isUnmounted) {
+ this.setState({
+ relayerInfos: undefined,
+ error: undefined,
+ });
+ }
const relayerInfos = await backendClient.getRelayerInfosAsync();
if (!this._isUnmounted) {
this.setState({
@@ -96,3 +114,31 @@ export class RelayerIndex extends React.Component<RelayerIndexProps, RelayerInde
}
}
}
+
+interface RetryProps {
+ onRetry: () => void;
+}
+const Retry = (props: RetryProps) => (
+ <div className="clearfix center" style={{ color: colors.black }}>
+ <div className="mx-auto inline-block align-middle" style={{ lineHeight: '44px', textAlign: 'center' }}>
+ <div className="h2" style={{ fontFamily: 'Roboto Mono' }}>
+ Something went wrong.
+ </div>
+ <div className="py3">
+ <FlatButton
+ label={'reload'}
+ backgroundColor={colors.black}
+ labelStyle={{
+ fontSize: 18,
+ fontFamily: 'Roboto Mono',
+ fontWeight: 'lighter',
+ color: colors.white,
+ textTransform: 'lowercase',
+ }}
+ style={{ width: 280, height: 62, borderRadius: 5 }}
+ onClick={props.onRetry}
+ />
+ </div>
+ </div>
+ </div>
+);
diff --git a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
index 233590b78..db4d3a211 100644
--- a/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
+++ b/packages/website/ts/components/relayer_index/relayer_top_tokens.tsx
@@ -3,10 +3,10 @@ import * as _ from 'lodash';
import * as React from 'react';
import { TokenIcon } from 'ts/components/ui/token_icon';
-import { Token } from 'ts/types';
+import { WebsiteBackendTokenInfo } from 'ts/types';
export interface TopTokensProps {
- tokens: Token[];
+ tokens: WebsiteBackendTokenInfo[];
networkId: number;
}
@@ -23,17 +23,17 @@ const styles: Styles = {
export const TopTokens: React.StatelessComponent<TopTokensProps> = (props: TopTokensProps) => {
return (
<div className="flex">
- {_.map(props.tokens, (token: Token, index: number) => {
+ {_.map(props.tokens, (tokenInfo: WebsiteBackendTokenInfo, index: number) => {
const firstItemStyle = { ...styles.tokenLabel, ...styles.followingTokenLabel };
const style = index !== 0 ? firstItemStyle : styles.tokenLabel;
return (
<a
- key={token.address}
- href={tokenLinkFromToken(token, props.networkId)}
+ key={tokenInfo.address}
+ href={tokenLinkFromToken(tokenInfo, props.networkId)}
target="_blank"
style={style}
>
- {token.symbol}
+ {tokenInfo.symbol}
</a>
);
})}
@@ -41,6 +41,6 @@ export const TopTokens: React.StatelessComponent<TopTokensProps> = (props: TopTo
);
};
-function tokenLinkFromToken(token: Token, networkId: number) {
- return sharedUtils.getEtherScanLinkIfExists(token.address, networkId, EtherscanLinkSuffixes.Address);
+function tokenLinkFromToken(tokenInfo: WebsiteBackendTokenInfo, networkId: number) {
+ return sharedUtils.getEtherScanLinkIfExists(tokenInfo.address, networkId, EtherscanLinkSuffixes.Address);
}
diff --git a/packages/website/ts/components/top_bar/provider_display.tsx b/packages/website/ts/components/top_bar/provider_display.tsx
index 221c34f8c..4cd50dba9 100644
--- a/packages/website/ts/components/top_bar/provider_display.tsx
+++ b/packages/website/ts/components/top_bar/provider_display.tsx
@@ -1,4 +1,4 @@
-import { colors } from '@0xproject/react-shared';
+import { colors, Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
import RaisedButton from 'material-ui/RaisedButton';
import * as React from 'react';
@@ -11,9 +11,9 @@ import { ProviderType } from 'ts/types';
import { constants } from 'ts/utils/constants';
import { utils } from 'ts/utils/utils';
-const IDENTICON_DIAMETER = 32;
+const ROOT_HEIGHT = 24;
-interface ProviderDisplayProps {
+export interface ProviderDisplayProps {
dispatcher: Dispatcher;
userAddress: string;
networkId: number;
@@ -25,6 +25,15 @@ interface ProviderDisplayProps {
interface ProviderDisplayState {}
+const styles: Styles = {
+ root: {
+ height: ROOT_HEIGHT,
+ backgroundColor: colors.white,
+ borderRadius: ROOT_HEIGHT,
+ boxShadow: `0px 4px 6px ${colors.walletBoxShadow}`,
+ },
+};
+
export class ProviderDisplay extends React.Component<ProviderDisplayProps, ProviderDisplayState> {
public render() {
const isAddressAvailable = !_.isEmpty(this.props.userAddress);
@@ -40,21 +49,20 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
: 'Connect a wallet';
const providerTitle =
this.props.providerType === ProviderType.Injected ? injectedProviderName : 'Ledger Nano S';
+ const isProviderMetamask = providerTitle === constants.PROVIDER_NAME_METAMASK;
const hoverActiveNode = (
- <div className="flex right lg-pr0 md-pr2 sm-pr2" style={{ paddingTop: 16 }}>
+ <div className="flex right lg-pr0 md-pr2 sm-pr2 p1" style={styles.root}>
<div>
- <Identicon address={this.props.userAddress} diameter={IDENTICON_DIAMETER} />
- </div>
- <div style={{ marginLeft: 12, paddingTop: 1 }}>
- <div style={{ fontSize: 12, color: colors.amber800 }}>{providerTitle}</div>
- <div style={{ fontSize: 14 }}>{displayAddress}</div>
+ <Identicon address={this.props.userAddress} diameter={ROOT_HEIGHT} />
</div>
- <div
- style={{ borderLeft: `1px solid ${colors.grey300}`, marginLeft: 17, paddingTop: 1 }}
- className="px2"
- >
- <i style={{ fontSize: 30, color: colors.grey300 }} className="zmdi zmdi zmdi-chevron-down" />
+ <div style={{ marginLeft: 12, paddingTop: 3 }}>
+ <div style={{ fontSize: 16, color: colors.darkGrey }}>{displayAddress}</div>
</div>
+ {isProviderMetamask && (
+ <div style={{ marginLeft: 16 }}>
+ <img src="/images/metamask_icon.png" style={{ width: ROOT_HEIGHT, height: ROOT_HEIGHT }} />
+ </div>
+ )}
</div>
);
const hasInjectedProvider =
diff --git a/packages/website/ts/components/top_bar/top_bar.tsx b/packages/website/ts/components/top_bar/top_bar.tsx
index 7fb476ba0..2502bea6d 100644
--- a/packages/website/ts/components/top_bar/top_bar.tsx
+++ b/packages/website/ts/components/top_bar/top_bar.tsx
@@ -19,7 +19,12 @@ import { Deco, Key, ProviderType, WebsiteLegacyPaths, WebsitePaths } from 'ts/ty
import { constants } from 'ts/utils/constants';
import { Translate } from 'ts/utils/translate';
-interface TopBarProps {
+export enum TopBarDisplayType {
+ Default,
+ Expanded,
+}
+
+export interface TopBarProps {
userAddress?: string;
networkId?: number;
injectedProviderName?: string;
@@ -34,7 +39,7 @@ interface TopBarProps {
availableDocVersions?: string[];
menu?: DocsMenu;
menuSubsectionsBySection?: MenuSubsectionsBySection;
- shouldFullWidth?: boolean;
+ displayType?: TopBarDisplayType;
docsInfo?: DocsInfo;
style?: React.CSSProperties;
isNightVersion?: boolean;
@@ -47,17 +52,8 @@ interface TopBarState {
}
const styles: Styles = {
- address: {
- marginRight: 12,
- overflow: 'hidden',
- paddingTop: 4,
- textOverflow: 'ellipsis',
- whiteSpace: 'nowrap',
- width: 70,
- },
topBar: {
backgroundColor: colors.white,
- height: 59,
width: '100%',
position: 'relative',
top: 0,
@@ -78,12 +74,19 @@ const styles: Styles = {
},
};
+const DEFAULT_HEIGHT = 59;
+const EXPANDED_HEIGHT = 75;
+
export class TopBar extends React.Component<TopBarProps, TopBarState> {
public static defaultProps: Partial<TopBarProps> = {
- shouldFullWidth: false,
+ displayType: TopBarDisplayType.Default,
style: {},
isNightVersion: false,
};
+ public static heightForDisplayType(displayType: TopBarDisplayType) {
+ const result = displayType === TopBarDisplayType.Expanded ? EXPANDED_HEIGHT : DEFAULT_HEIGHT;
+ return result + 1;
+ }
constructor(props: TopBarProps) {
super(props);
this.state = {
@@ -92,8 +95,9 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
}
public render() {
const isNightVersion = this.props.isNightVersion;
- const isFullWidthPage = this.props.shouldFullWidth;
- const parentClassNames = `flex mx-auto ${isFullWidthPage ? 'pl2' : 'max-width-4'}`;
+ const isExpandedDisplayType = this.props.displayType === TopBarDisplayType.Expanded;
+ const parentClassNames = `flex mx-auto ${isExpandedDisplayType ? 'pl3 py1' : 'max-width-4'}`;
+ const height = isExpandedDisplayType ? EXPANDED_HEIGHT : DEFAULT_HEIGHT;
const developerSectionMenuItems = [
<Link key="subMenuItem-zeroEx" to={WebsitePaths.ZeroExJs} className="text-decoration-none">
<MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="0x.js" />
@@ -178,9 +182,11 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
</a>,
];
const bottomBorderStyle = this._shouldDisplayBottomBar() ? styles.bottomBar : {};
- const fullWidthClasses = isFullWidthPage ? 'pr4' : '';
+ const fullWidthClasses = isExpandedDisplayType ? 'pr4' : '';
const logoUrl = isNightVersion ? '/images/protocol_logo_white.png' : '/images/protocol_logo_black.png';
- const menuClasses = `col col-${isFullWidthPage ? '4' : '5'} ${fullWidthClasses} lg-pr0 md-pr2 sm-hide xs-hide`;
+ const menuClasses = `col col-${
+ isExpandedDisplayType ? '4' : '5'
+ } ${fullWidthClasses} lg-pr0 md-pr2 sm-hide xs-hide`;
const menuIconStyle = {
fontSize: 25,
color: isNightVersion ? 'white' : 'black',
@@ -197,15 +203,15 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
);
const popoverContent = <Menu style={{ color: colors.darkGrey }}>{developerSectionMenuItems}</Menu>;
return (
- <div style={{ ...styles.topBar, ...bottomBorderStyle, ...this.props.style }} className="pb1">
+ <div style={{ ...styles.topBar, ...bottomBorderStyle, ...this.props.style, ...{ height } }} className="pb1">
<div className={parentClassNames}>
<div className="col col-2 sm-pl1 md-pl2 lg-pl0" style={{ paddingTop: 15 }}>
<Link to={`${WebsitePaths.Home}`} className="text-decoration-none">
<img src={logoUrl} height="30" />
</Link>
</div>
- <div className={`col col-${isFullWidthPage ? '8' : '9'} lg-hide md-hide`} />
- <div className={`col col-${isFullWidthPage ? '6' : '5'} sm-hide xs-hide`} />
+ <div className={`col col-${isExpandedDisplayType ? '8' : '9'} lg-hide md-hide`} />
+ <div className={`col col-${isExpandedDisplayType ? '6' : '5'} sm-hide xs-hide`} />
{!this._isViewingPortal() && (
<div className={menuClasses}>
<div className="flex justify-between">
@@ -242,7 +248,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
path={`${WebsitePaths.Portal}`}
isPrimary={true}
style={styles.menuItem}
- className={`${isFullWidthPage && 'md-hide'}`}
+ className={`${isExpandedDisplayType && 'md-hide'}`}
isNightVersion={isNightVersion}
isExternal={false}
/>
@@ -250,7 +256,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
</div>
)}
{this.props.blockchainIsLoaded && (
- <div className="sm-hide xs-hide col col-5">
+ <div className="sm-hide xs-hide col col-5" style={{ paddingTop: 8, marginRight: 36 }}>
<ProviderDisplay
dispatcher={this.props.dispatcher}
userAddress={this.props.userAddress}
@@ -262,7 +268,7 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
/>
</div>
)}
- <div className={`col ${isFullWidthPage ? 'col-2 pl2' : 'col-1'} md-hide lg-hide`}>
+ <div className={`col ${isExpandedDisplayType ? 'col-2 pl2' : 'col-1'} md-hide lg-hide`}>
<div style={menuIconStyle}>
<i className="zmdi zmdi-menu" onClick={this._onMenuButtonClick.bind(this)} />
</div>
@@ -441,21 +447,6 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
</div>
);
}
- private _renderUser() {
- const userAddress = this.props.userAddress;
- const identiconDiameter = 26;
- return (
- <div className="flex right lg-pr0 md-pr2 sm-pr2" style={{ paddingTop: 16 }}>
- <div style={styles.address} data-tip={true} data-for="userAddressTooltip">
- {!_.isEmpty(userAddress) ? userAddress : ''}
- </div>
- <ReactTooltip id="userAddressTooltip">{userAddress}</ReactTooltip>
- <div>
- <Identicon address={userAddress} diameter={identiconDiameter} />
- </div>
- </div>
- );
- }
private _onMenuButtonClick() {
this.setState({
isDrawerOpen: !this.state.isDrawerOpen,
@@ -511,7 +502,8 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> {
this._isViewingJsonSchemasDocs() ||
this._isViewingSolCovDocs() ||
this._isViewingSubprovidersDocs() ||
- this._isViewingConnectDocs()
+ this._isViewingConnectDocs() ||
+ this._isViewingPortal()
);
}
} // tslint:disable:max-file-line-count
diff --git a/packages/website/ts/components/wallet/wallet.tsx b/packages/website/ts/components/wallet/wallet.tsx
index 057c712e5..a28012aaf 100644
--- a/packages/website/ts/components/wallet/wallet.tsx
+++ b/packages/website/ts/components/wallet/wallet.tsx
@@ -55,11 +55,13 @@ export interface WalletProps {
injectedProviderName: string;
providerType: ProviderType;
onToggleLedgerDialog: () => void;
+ onAddToken: () => void;
}
interface WalletState {
trackedTokenStateByAddress: TokenStateByAddress;
wrappedEtherDirection?: Side;
+ isHoveringSidebar: boolean;
}
interface AllowanceToggleConfig {
@@ -94,6 +96,9 @@ const styles: Styles = {
},
footerItemInnerDiv: {
paddingLeft: 24,
+ borderTopColor: colors.walletBorder,
+ borderTopStyle: 'solid',
+ borderWidth: 1,
},
borderedItem: {
borderBottomColor: colors.walletBorder,
@@ -114,7 +119,17 @@ const styles: Styles = {
paddingTop: 8,
paddingBottom: 8,
},
- accessoryItemsContainer: { width: 150, right: 8 },
+ accessoryItemsContainer: {
+ width: 150,
+ right: 8,
+ },
+ bodyInnerDiv: {
+ padding: 0,
+ // TODO: make this completely responsive
+ maxHeight: 475,
+ overflow: 'auto',
+ WebkitOverflowScrolling: 'touch',
+ },
};
const ETHER_ICON_PATH = '/images/ether.png';
@@ -139,6 +154,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
this.state = {
trackedTokenStateByAddress: initialTrackedTokenStateByAddress,
wrappedEtherDirection: undefined,
+ isHoveringSidebar: false,
};
}
public componentWillMount() {
@@ -184,12 +200,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
return (
<List style={styles.list}>
{isAddressAvailable
- ? _.concat(
- this._renderConnectedHeaderRows(),
- this._renderEthRows(),
- this._renderTokenRows(),
- this._renderFooterRows(),
- )
+ ? _.concat(this._renderConnectedHeaderRows(), this._renderBody(), this._renderFooterRows())
: _.concat(this._renderDisconnectedHeaderRows(), this._renderDisconnectedRows())}
</List>
);
@@ -230,9 +241,43 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
/>
);
}
+ private _renderBody() {
+ const bodyStyle: React.CSSProperties = {
+ ...styles.bodyInnerDiv,
+ overflow: this.state.isHoveringSidebar ? 'auto' : 'hidden',
+ };
+ return (
+ <ListItem
+ key="body"
+ innerDivStyle={bodyStyle}
+ onMouseEnter={this._onSidebarHover.bind(this)}
+ onMouseLeave={this._onSidebarHoverOff.bind(this)}
+ >
+ {this._renderEthRows()}
+ {this._renderTokenRows()}
+ </ListItem>
+ );
+ }
+ private _onSidebarHover(event: React.FormEvent<HTMLInputElement>) {
+ this.setState({
+ isHoveringSidebar: true,
+ });
+ }
+ private _onSidebarHoverOff() {
+ this.setState({
+ isHoveringSidebar: false,
+ });
+ }
private _renderFooterRows() {
const primaryText = '+ other tokens';
- return <ListItem key={FOOTER_ITEM_KEY} primaryText={primaryText} innerDivStyle={styles.footerItemInnerDiv} />;
+ return (
+ <ListItem
+ key={FOOTER_ITEM_KEY}
+ primaryText={primaryText}
+ innerDivStyle={styles.footerItemInnerDiv}
+ onClick={this.props.onAddToken}
+ />
+ );
}
private _renderEthRows() {
const primaryText = this._renderAmount(
@@ -293,7 +338,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
);
return _.map(trackedTokensStartingWithEtherToken, this._renderTokenRow.bind(this));
}
- private _renderTokenRow(token: Token) {
+ private _renderTokenRow(token: Token, index: number) {
const tokenState = this.state.trackedTokenStateByAddress[token.address];
const tokenLink = sharedUtils.getEtherScanLinkIfExists(
token.address,
@@ -310,12 +355,14 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
tokenState,
},
};
+ // if this is the last item in the list, do not render the border, it is rendered by the footer
+ const borderedStyle = index !== this.props.trackedTokens.length - 1 ? styles.borderedItem : {};
const shouldShowWrapEtherItem =
!_.isUndefined(this.state.wrappedEtherDirection) &&
this.state.wrappedEtherDirection === accessoryItemConfig.wrappedEtherDirection;
const style = shouldShowWrapEtherItem
? { ...walletItemStyles.focusedItem, ...styles.paddedItem }
- : { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem };
+ : { ...styles.tokenItem, ...borderedStyle, ...styles.paddedItem };
const etherToken = this._getEthToken();
return (
<div key={token.address}>
diff --git a/packages/website/ts/containers/portal.ts b/packages/website/ts/containers/portal.ts
new file mode 100644
index 000000000..3f0feb6e9
--- /dev/null
+++ b/packages/website/ts/containers/portal.ts
@@ -0,0 +1,88 @@
+import { BigNumber } from '@0xproject/utils';
+import * as _ from 'lodash';
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Dispatch } from 'redux';
+import { Portal as PortalComponent, PortalProps as PortalComponentProps } from 'ts/components/portal/portal';
+import { Dispatcher } from 'ts/redux/dispatcher';
+import { State } from 'ts/redux/reducer';
+import { BlockchainErrs, HashData, Order, ProviderType, ScreenWidths, Side, TokenByAddress } from 'ts/types';
+import { constants } from 'ts/utils/constants';
+import { Translate } from 'ts/utils/translate';
+
+interface ConnectedState {
+ blockchainErr: BlockchainErrs;
+ blockchainIsLoaded: boolean;
+ hashData: HashData;
+ injectedProviderName: string;
+ networkId: number;
+ nodeVersion: string;
+ orderFillAmount: BigNumber;
+ providerType: ProviderType;
+ tokenByAddress: TokenByAddress;
+ lastForceTokenStateRefetch: number;
+ userEtherBalanceInWei: BigNumber;
+ screenWidth: ScreenWidths;
+ shouldBlockchainErrDialogBeOpen: boolean;
+ userAddress: string;
+ userSuppliedOrderCache: Order;
+ flashMessage?: string | React.ReactNode;
+ translate: Translate;
+}
+
+interface ConnectedDispatch {
+ dispatcher: Dispatcher;
+}
+
+const mapStateToProps = (state: State, ownProps: PortalComponentProps): ConnectedState => {
+ const receiveAssetToken = state.sideToAssetToken[Side.Receive];
+ const depositAssetToken = state.sideToAssetToken[Side.Deposit];
+ const receiveAddress = !_.isUndefined(receiveAssetToken.address)
+ ? receiveAssetToken.address
+ : constants.NULL_ADDRESS;
+ const depositAddress = !_.isUndefined(depositAssetToken.address)
+ ? depositAssetToken.address
+ : constants.NULL_ADDRESS;
+ const receiveAmount = !_.isUndefined(receiveAssetToken.amount) ? receiveAssetToken.amount : new BigNumber(0);
+ const depositAmount = !_.isUndefined(depositAssetToken.amount) ? depositAssetToken.amount : new BigNumber(0);
+ const hashData = {
+ depositAmount,
+ depositTokenContractAddr: depositAddress,
+ feeRecipientAddress: constants.NULL_ADDRESS,
+ makerFee: constants.MAKER_FEE,
+ orderExpiryTimestamp: state.orderExpiryTimestamp,
+ orderMakerAddress: state.userAddress,
+ orderTakerAddress: state.orderTakerAddress !== '' ? state.orderTakerAddress : constants.NULL_ADDRESS,
+ receiveAmount,
+ receiveTokenContractAddr: receiveAddress,
+ takerFee: constants.TAKER_FEE,
+ orderSalt: state.orderSalt,
+ };
+ return {
+ blockchainErr: state.blockchainErr,
+ blockchainIsLoaded: state.blockchainIsLoaded,
+ hashData,
+ injectedProviderName: state.injectedProviderName,
+ networkId: state.networkId,
+ nodeVersion: state.nodeVersion,
+ orderFillAmount: state.orderFillAmount,
+ providerType: state.providerType,
+ screenWidth: state.screenWidth,
+ shouldBlockchainErrDialogBeOpen: state.shouldBlockchainErrDialogBeOpen,
+ tokenByAddress: state.tokenByAddress,
+ lastForceTokenStateRefetch: state.lastForceTokenStateRefetch,
+ userAddress: state.userAddress,
+ userEtherBalanceInWei: state.userEtherBalanceInWei,
+ userSuppliedOrderCache: state.userSuppliedOrderCache,
+ flashMessage: state.flashMessage,
+ translate: state.translate,
+ };
+};
+
+const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
+ dispatcher: new Dispatcher(dispatch),
+});
+
+export const Portal: React.ComponentClass<PortalComponentProps> = connect(mapStateToProps, mapDispatchToProps)(
+ PortalComponent,
+);
diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx
index 9535dd222..1b1255214 100644
--- a/packages/website/ts/index.tsx
+++ b/packages/website/ts/index.tsx
@@ -34,9 +34,14 @@ import 'less/all.less';
// cause we only want to import the module when the user navigates to the page.
// At the same time webpack statically parses for System.import() to determine bundle chunk split points
// so each lazy import needs it's own `System.import()` declaration.
-const LazyPortal = createLazyComponent('LegacyPortal', async () =>
- System.import<any>(/* webpackChunkName: "legacyPortal" */ 'ts/containers/legacy_portal'),
-);
+const LazyPortal =
+ utils.isDevelopment() || utils.isStaging()
+ ? createLazyComponent('Portal', async () =>
+ System.import<any>(/* webpackChunkName: "portal" */ 'ts/containers/portal'),
+ )
+ : createLazyComponent('LegacyPortal', async () =>
+ System.import<any>(/* webpackChunkName: "legacyPortal" */ 'ts/containers/legacy_portal'),
+ );
const LazyZeroExJSDocumentation = createLazyComponent('Documentation', async () =>
System.import<any>(/* webpackChunkName: "zeroExDocs" */ 'ts/containers/zero_ex_js_documentation'),
);
diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts
index 2754075a7..67e4a5d7d 100644
--- a/packages/website/ts/types.ts
+++ b/packages/website/ts/types.ts
@@ -503,19 +503,26 @@ export interface TokenState {
price?: BigNumber;
}
-// TODO: Add topTokens property once available from backend
export interface WebsiteBackendRelayerInfo {
name: string;
dailyTxnVolume: string;
url: string;
appUrl?: string;
- headerImgUrl: string;
+ headerImgUrl?: string;
+ topTokens: WebsiteBackendTokenInfo[];
}
export interface WebsiteBackendPriceInfo {
[symbol: string]: string;
}
+export interface WebsiteBackendTokenInfo {
+ address: string;
+ decimals: number;
+ name: string;
+ symbol: string;
+}
+
export interface WebsiteBackendGasInfo {
average: number;
}