From 1f05f67fe45d02c98e673446a5f93ebdb2855c74 Mon Sep 17 00:00:00 2001 From: zachdaniel Date: Wed, 27 Mar 2019 18:22:14 -0400 Subject: [PATCH] feat: verify contracts via an RPC endpoint --- CHANGELOG.md | 1 + .../api/rpc/contract_controller.ex | 85 +++++++++ .../lib/block_scout_web/etherscan.ex | 166 +++++++++++++++++- .../views/api/rpc/contract_view.ex | 4 + .../api/rpc/contract_controller_test.exs | 97 ++++++++++ .../smart_contract/compiler_tests.json | 13 ++ 6 files changed, 365 insertions(+), 1 deletion(-) create mode 100644 apps/block_scout_web/test/support/fixture/smart_contract/compiler_tests.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d2255cf86..a046a1a134 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [#1662](https://github.com/poanetwork/blockscout/pull/1662) - allow specifying number of optimization runs - [#1654](https://github.com/poanetwork/blockscout/pull/1654) - add decompiled code tab - [#1661](https://github.com/poanetwork/blockscout/pull/1661) - try to compile smart contract with the latest evm version + - [#1665](https://github.com/poanetwork/blockscout/pull/1665) - Add contract verification RPC endpoint. ### Fixes diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex index d2aa6fb07b..146626cce5 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex @@ -4,6 +4,24 @@ defmodule BlockScoutWeb.API.RPC.ContractController do alias BlockScoutWeb.API.RPC.Helpers alias Explorer.Chain alias Explorer.Chain.SmartContract + alias Explorer.SmartContract.Publisher + + def verify(conn, %{"addressHash" => address_hash} = params) do + with {:params, {:ok, fetched_params}} <- {:params, fetch_verify_params(params)}, + {:params, external_libraries} <- + {:params, fetch_external_libraries(params)}, + {:publish, {:ok, smart_contract}} <- + {:publish, Publisher.publish(address_hash, fetched_params, external_libraries)}, + preloaded_smart_contract <- SmartContract.preload_decompiled_smart_contract(smart_contract) do + render(conn, :verify, %{contract: preloaded_smart_contract, address_hash: address_hash}) + else + {:publish, _} -> + render(conn, :error, error: "Something went wrong while publishing the contract.") + + {:params, {:error, error}} -> + render(conn, :error, error: error) + end + end def listcontracts(conn, params) do with pagination_options <- Helpers.put_pagination_options(%{}, params), @@ -155,4 +173,71 @@ defmodule BlockScoutWeb.API.RPC.ContractController do {:contract, result} end + + defp fetch_verify_params(params) do + {:ok, %{}} + |> required_param(params, "addressHash", "address_hash") + |> required_param(params, "name", "name") + |> required_param(params, "compilerVersion", "compiler_version") + |> required_param(params, "optimization", "optimization") + |> required_param(params, "contractSourceCode", "contract_source_code") + |> optional_param(params, "evmVersion", "evm_version") + |> optional_param(params, "constructorArguments", "constructor_arguments") + |> optional_param(params, "optimizationRuns", "optimization_runs") + |> parse_optimization_runs() + end + + defp parse_optimization_runs({:ok, %{"optimization_runs" => runs} = opts}) when is_bitstring(runs) do + {:ok, Map.put(opts, "optimization_runs", 200)} + end + + defp parse_optimization_runs({:ok, %{"optimization_runs" => runs} = opts}) when is_integer(runs) do + {:ok, opts} + end + + defp parse_optimization_runs({:ok, opts}) do + {:ok, Map.put(opts, "optimization_runs", 200)} + end + + defp parse_optimization_runs(other), do: other + + defp fetch_external_libraries(params) do + Enum.reduce(1..5, %{}, fn number, acc -> + case Map.fetch(params, "library#{number}Name") do + {:ok, library_name} -> + library_address = Map.get(params, "library#{number}Address") + + acc + |> Map.put("library#{number}_name", library_name) + |> Map.put("library#{number}_address", library_address) + + :error -> + acc + end + end) + end + + defp required_param({:error, _} = error, _, _, _), do: error + + defp required_param({:ok, map}, params, key, new_key) do + case Map.fetch(params, key) do + {:ok, value} -> + {:ok, Map.put(map, new_key, value)} + + :error -> + {:error, "#{key} is required."} + end + end + + defp optional_param({:error, _} = error, _, _, _), do: error + + defp optional_param({:ok, map}, params, key, new_key) do + case Map.fetch(params, key) do + {:ok, value} -> + {:ok, Map.put(map, new_key, value)} + + :error -> + {:ok, map} + end + end end diff --git a/apps/block_scout_web/lib/block_scout_web/etherscan.ex b/apps/block_scout_web/lib/block_scout_web/etherscan.ex index 07b7b5056b..d68f0c95c7 100644 --- a/apps/block_scout_web/lib/block_scout_web/etherscan.ex +++ b/apps/block_scout_web/lib/block_scout_web/etherscan.ex @@ -328,6 +328,49 @@ defmodule BlockScoutWeb.Etherscan do "result" => nil } + @contract_verify_example_value %{ + "status" => "1", + "message" => "OK", + "result" => %{ + "SourceCode" => """ + pragma solidity >0.4.24; + + contract Test { + constructor() public { b = hex"12345678901234567890123456789012"; } + event Event(uint indexed a, bytes32 b); + event Event2(uint indexed a, bytes32 b); + function foo(uint a) public { emit Event(a, b); } + bytes32 b; + } + """, + "ABI" => """ + [{ + "type":"event", + "inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"bytes32","indexed":false}], + "name":"Event" + }, { + "type":"event", + "inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"bytes32","indexed":false}], + "name":"Event2" + }, { + "type":"function", + "inputs": [{"name":"a","type":"uint256"}], + "name":"foo", + "outputs": [] + }] + """, + "ContractName" => "Test", + "CompilerVersion" => "v0.2.1-2016-01-30-91a6b35", + "OptimizationUsed" => "1" + } + } + + @contract_verify_example_value_error %{ + "status" => "0", + "message" => "There was an error verifying the contract.", + "result" => nil + } + @contract_getsourcecode_example_value %{ "status" => "1", "message" => "OK", @@ -1747,6 +1790,126 @@ defmodule BlockScoutWeb.Etherscan do ] } + @contract_verify_action %{ + name: "verify", + description: "Verify a contract with its source code and contract creation information.", + required_params: [ + %{ + key: "addressHash", + placeholder: "addressHash", + type: "string", + description: "The address of the contract." + }, + %{ + key: "name", + placeholder: "name", + type: "string", + description: "The name of the contract." + }, + %{ + key: "compilerVersion", + placeholder: "compilerVersion", + type: "string", + description: "The compiler version for the contract." + }, + %{ + key: "optimization", + placeholder: false, + type: "boolean", + description: "Whether or not compiler optimizations were enabled." + }, + %{ + key: "contractSourceCode", + placeholder: "contractSourceCode", + type: "string", + description: "The source code of the contract." + } + ], + optional_params: [ + %{ + key: "constructorArguments", + type: "string", + description: "The constructor argument data provided." + }, + %{ + key: "evmVersion", + placeholder: "evmVersion", + type: "string", + description: "The EVM version for the contract." + }, + %{ + key: "optimizationRuns", + placeholder: "optimizationRuns", + type: "integer", + description: "The number of optimization runs used during compilation" + }, + %{ + key: "library1Name", + type: "string", + description: "The name of the first library used." + }, + %{ + key: "library1Address", + type: "string", + description: "The address of the first library used." + }, + %{ + key: "library2Name", + type: "string", + description: "The name of the second library used." + }, + %{ + key: "library2Address", + type: "string", + description: "The address of the second library used." + }, + %{ + key: "library3Name", + type: "string", + description: "The name of the third library used." + }, + %{ + key: "library3Address", + type: "string", + description: "The address of the third library used." + }, + %{ + key: "library4Name", + type: "string", + description: "The name of the fourth library used." + }, + %{ + key: "library4Address", + type: "string", + description: "The address of the fourth library used." + }, + %{ + key: "library5Name", + type: "string", + description: "The name of the fourth library used." + }, + %{ + key: "library5Address", + type: "string", + description: "The address of the fourth library used." + } + ], + responses: [ + %{ + code: "200", + description: "successful operation", + example_value: Jason.encode!(@contract_verify_example_value), + type: "model", + model: @contract_model + }, + %{ + code: "200", + description: "error", + example_value: Jason.encode!(@contract_verify_example_value_error) + } + ] + } + @contract_getabi_action %{ name: "getabi", description: "Get ABI for verified contract. Also available through a GraphQL 'addresses' query.", @@ -1976,7 +2139,8 @@ defmodule BlockScoutWeb.Etherscan do actions: [ @contract_listcontracts_action, @contract_getabi_action, - @contract_getsourcecode_action + @contract_getsourcecode_action, + @contract_verify_action ] } diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/contract_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/contract_view.ex index c2c593a313..27e049dfc3 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/contract_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/contract_view.ex @@ -22,6 +22,10 @@ defmodule BlockScoutWeb.API.RPC.ContractView do RPCView.render("error.json", assigns) end + def render("verify.json", %{contract: contract, address_hash: address_hash}) do + RPCView.render("show.json", data: prepare_source_code_contract(contract, address_hash)) + end + defp prepare_source_code_contract(nil, address_hash) do %{ "Address" => to_string(address_hash), diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs index d299d6bc73..632809863f 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do use BlockScoutWeb.ConnCase + alias Explorer.Factory describe "listcontracts" do setup do @@ -413,4 +414,100 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do assert response["message"] == "OK" end end + + describe "verify" do + test "with an address that doesn't exist", %{conn: conn} do + contract_code_info = Factory.contract_code_info() + + contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) + + params = %{ + "module" => "contract", + "action" => "verify", + "addressHash" => to_string(contract_address.hash), + "name" => contract_code_info.name, + "compilerVersion" => contract_code_info.version, + "optimization" => contract_code_info.optimized, + "contractSourceCode" => contract_code_info.source_code + } + + response = + conn + |> get("/api", params) + |> json_response(200) + + expected_result = %{ + "Address" => to_string(contract_address.hash), + "SourceCode" => contract_code_info.source_code, + "ABI" => Jason.encode!(contract_code_info.abi), + "ContractName" => contract_code_info.name, + "CompilerVersion" => contract_code_info.version, + "DecompiledSourceCode" => "Contract source code not decompiled.", + "DecompilerVersion" => "", + "OptimizationUsed" => "0" + } + + assert response["status"] == "1" + assert response["result"] == expected_result + assert response["message"] == "OK" + end + + test "with external libraries", %{conn: conn} do + contract_data = + "#{File.cwd!()}/test/support/fixture/smart_contract/compiler_tests.json" + |> File.read!() + |> Jason.decode!() + |> List.first() + + %{ + "compiler_version" => compiler_version, + "external_libraries" => external_libraries, + "name" => name, + "optimize" => optimize, + "contract" => contract_source_code, + "expected_bytecode" => expected_bytecode + } = contract_data + + contract_address = insert(:contract_address, contract_code: "0x" <> expected_bytecode) + + params = %{ + "module" => "contract", + "action" => "verify", + "addressHash" => to_string(contract_address.hash), + "name" => name, + "compilerVersion" => compiler_version, + "optimization" => optimize, + "contractSourceCode" => contract_source_code + } + + params_with_external_libraries = + external_libraries + |> Enum.with_index() + |> Enum.reduce(params, fn {{name, address}, index}, acc -> + name_key = "library#{index + 1}Name" + address_key = "library#{index + 1}Address" + + acc + |> Map.put(name_key, name) + |> Map.put(address_key, address) + end) + + response = + conn + |> get("/api", params_with_external_libraries) + |> json_response(200) + + assert response["status"] == "1" + assert response["message"] == "OK" + + result = response["result"] + + assert result["Address"] == to_string(contract_address.hash) + assert result["SourceCode"] == contract_source_code + assert result["ContractName"] == name + assert result["DecompiledSourceCode"] == "Contract source code not decompiled." + assert result["DecompilerVersion"] == "" + assert result["OptimizationUsed"] == "1" + end + end end diff --git a/apps/block_scout_web/test/support/fixture/smart_contract/compiler_tests.json b/apps/block_scout_web/test/support/fixture/smart_contract/compiler_tests.json new file mode 100644 index 0000000000..f74cd3d707 --- /dev/null +++ b/apps/block_scout_web/test/support/fixture/smart_contract/compiler_tests.json @@ -0,0 +1,13 @@ +[ + { + "compiler_version": "v0.4.11+commit.68ef5810", + "contract": "pragma solidity ^0.4.11;\n/**\n * @title ERC20Basic\n * @dev Simpler version of ERC20 interface\n * @dev see https://github.com/ethereum/EIPs/issues/179\n */\ncontract ERC20Basic {\n uint256 public totalSupply;\n function balanceOf(address who) public constant returns (uint256);\n function transfer(address to, uint256 value) public returns (bool);\n event Transfer(address indexed from, address indexed to, uint256 value);\n}\n/**\n * @title Ownable\n * @dev The Ownable contract has an owner address, and provides basic authorization control\n * functions, this simplifies the implementation of \"user permissions\".\n */\ncontract Ownable {\n address public owner;\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n /**\n * @dev The Ownable constructor sets the original `owner` of the contract to the sender\n * account.\n */\n function Ownable() {\n owner = msg.sender;\n }\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(msg.sender == owner);\n _;\n }\n /**\n * @dev Allows the current owner to transfer control of the contract to a newOwner.\n * @param newOwner The address to transfer ownership to.\n */\n function transferOwnership(address newOwner) onlyOwner public {\n require(newOwner != address(0));\n OwnershipTransferred(owner, newOwner);\n owner = newOwner;\n }\n}\n// Temporarily have SafeMath here until all contracts have been migrated to SafeMathLib version from OpenZeppelin\n/**\n * Math operations with safety checks\n */\ncontract SafeMath {\n function safeMul(uint a, uint b) internal returns (uint) {\n uint c = a * b;\n assert(a == 0 || c / a == b);\n return c;\n }\n function safeDiv(uint a, uint b) internal returns (uint) {\n assert(b > 0);\n uint c = a / b;\n assert(a == b * c + a % b);\n return c;\n }\n function safeSub(uint a, uint b) internal returns (uint) {\n assert(b <= a);\n return a - b;\n }\n function safeAdd(uint a, uint b) internal returns (uint) {\n uint c = a + b;\n assert(c>=a && c>=b);\n return c;\n }\n function max64(uint64 a, uint64 b) internal constant returns (uint64) {\n return a >= b ? a : b;\n }\n function min64(uint64 a, uint64 b) internal constant returns (uint64) {\n return a < b ? a : b;\n }\n function max256(uint256 a, uint256 b) internal constant returns (uint256) {\n return a >= b ? a : b;\n }\n function min256(uint256 a, uint256 b) internal constant returns (uint256) {\n return a < b ? a : b;\n }\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * @title ERC20 interface\n * @dev see https://github.com/ethereum/EIPs/issues/20\n */\ncontract ERC20 is ERC20Basic {\n function allowance(address owner, address spender) public constant returns (uint256);\n function transferFrom(address from, address to, uint256 value) public returns (bool);\n function approve(address spender, uint256 value) public returns (bool);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n/**\n * Standard ERC20 token with Short Hand Attack and approve() race condition mitigation.\n *\n * Based on code by FirstBlood:\n * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol\n */\ncontract StandardToken is ERC20, SafeMath {\n /* Token supply got increased and a new owner received these tokens */\n event Minted(address receiver, uint amount);\n /* Actual balances of token holders */\n mapping(address => uint) balances;\n /* approve() allowances */\n mapping (address => mapping (address => uint)) allowed;\n /* Interface declaration */\n function isToken() public constant returns (bool weAre) {\n return true;\n }\n function transfer(address _to, uint _value) returns (bool success) {\n balances[msg.sender] = safeSub(balances[msg.sender], _value);\n balances[_to] = safeAdd(balances[_to], _value);\n Transfer(msg.sender, _to, _value);\n return true;\n }\n function transferFrom(address _from, address _to, uint _value) returns (bool success) {\n uint _allowance = allowed[_from][msg.sender];\n balances[_to] = safeAdd(balances[_to], _value);\n balances[_from] = safeSub(balances[_from], _value);\n allowed[_from][msg.sender] = safeSub(_allowance, _value);\n Transfer(_from, _to, _value);\n return true;\n }\n function balanceOf(address _owner) constant returns (uint balance) {\n return balances[_owner];\n }\n function approve(address _spender, uint _value) returns (bool success) {\n // To change the approve amount you first have to reduce the addresses`\n // allowance to zero by calling `approve(_spender, 0)` if it is not\n // already 0 to mitigate the race condition described here:\n // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n if ((_value != 0) && (allowed[msg.sender][_spender] != 0)) throw;\n allowed[msg.sender][_spender] = _value;\n Approval(msg.sender, _spender, _value);\n return true;\n }\n function allowance(address _owner, address _spender) constant returns (uint remaining) {\n return allowed[_owner][_spender];\n }\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * Upgrade agent interface inspired by Lunyr.\n *\n * Upgrade agent transfers tokens to a new contract.\n * Upgrade agent itself can be the token contract, or just a middle man contract doing the heavy lifting.\n */\ncontract UpgradeAgent {\n uint public originalSupply;\n /** Interface marker */\n function isUpgradeAgent() public constant returns (bool) {\n return true;\n }\n function upgradeFrom(address _from, uint256 _value) public;\n}\n/**\n * A token upgrade mechanism where users can opt-in amount of tokens to the next smart contract revision.\n *\n * First envisioned by Golem and Lunyr projects.\n */\ncontract UpgradeableToken is StandardToken {\n /** Contract / person who can set the upgrade path. This can be the same as team multisig wallet, as what it is with its default value. */\n address public upgradeMaster;\n /** The next contract where the tokens will be migrated. */\n UpgradeAgent public upgradeAgent;\n /** How many tokens we have upgraded by now. */\n uint256 public totalUpgraded;\n /**\n * Upgrade states.\n *\n * - NotAllowed: The child contract has not reached a condition where the upgrade can bgun\n * - WaitingForAgent: Token allows upgrade, but we don't have a new agent yet\n * - ReadyToUpgrade: The agent is set, but not a single token has been upgraded yet\n * - Upgrading: Upgrade agent is set and the balance holders can upgrade their tokens\n *\n */\n enum UpgradeState {Unknown, NotAllowed, WaitingForAgent, ReadyToUpgrade, Upgrading}\n /**\n * Somebody has upgraded some of his tokens.\n */\n event Upgrade(address indexed _from, address indexed _to, uint256 _value);\n /**\n * New upgrade agent available.\n */\n event UpgradeAgentSet(address agent);\n /**\n * Do not allow construction without upgrade master set.\n */\n function UpgradeableToken(address _upgradeMaster) {\n upgradeMaster = _upgradeMaster;\n }\n /**\n * Allow the token holder to upgrade some of their tokens to a new contract.\n */\n function upgrade(uint256 value) public {\n UpgradeState state = getUpgradeState();\n if(!(state == UpgradeState.ReadyToUpgrade || state == UpgradeState.Upgrading)) {\n // Called in a bad state\n throw;\n }\n // Validate input value.\n if (value == 0) throw;\n balances[msg.sender] = safeSub(balances[msg.sender], value);\n // Take tokens out from circulation\n totalSupply = safeSub(totalSupply, value);\n totalUpgraded = safeAdd(totalUpgraded, value);\n // Upgrade agent reissues the tokens\n upgradeAgent.upgradeFrom(msg.sender, value);\n Upgrade(msg.sender, upgradeAgent, value);\n }\n /**\n * Set an upgrade agent that handles\n */\n function setUpgradeAgent(address agent) external {\n if(!canUpgrade()) {\n // The token is not yet in a state that we could think upgrading\n throw;\n }\n if (agent == 0x0) throw;\n // Only a master can designate the next agent\n if (msg.sender != upgradeMaster) throw;\n // Upgrade has already begun for an agent\n if (getUpgradeState() == UpgradeState.Upgrading) throw;\n upgradeAgent = UpgradeAgent(agent);\n // Bad interface\n if(!upgradeAgent.isUpgradeAgent()) throw;\n // Make sure that token supplies match in source and target\n if (upgradeAgent.originalSupply() != totalSupply) throw;\n UpgradeAgentSet(upgradeAgent);\n }\n /**\n * Get the state of the token upgrade.\n */\n function getUpgradeState() public constant returns(UpgradeState) {\n if(!canUpgrade()) return UpgradeState.NotAllowed;\n else if(address(upgradeAgent) == 0x00) return UpgradeState.WaitingForAgent;\n else if(totalUpgraded == 0) return UpgradeState.ReadyToUpgrade;\n else return UpgradeState.Upgrading;\n }\n /**\n * Change the upgrade master.\n *\n * This allows us to set a new owner for the upgrade mechanism.\n */\n function setUpgradeMaster(address master) public {\n if (master == 0x0) throw;\n if (msg.sender != upgradeMaster) throw;\n upgradeMaster = master;\n }\n /**\n * Child contract can enable to provide the condition when the upgrade can begun.\n */\n function canUpgrade() public constant returns(bool) {\n return true;\n }\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * Define interface for releasing the token transfer after a successful crowdsale.\n */\ncontract ReleasableToken is ERC20, Ownable {\n /* The finalizer contract that allows unlift the transfer limits on this token */\n address public releaseAgent;\n /** A crowdsale contract can release us to the wild if ICO success. If false we are are in transfer lock up period.*/\n bool public released = false;\n /** Map of agents that are allowed to transfer tokens regardless of the lock down period. These are crowdsale contracts and possible the team multisig itself. */\n mapping (address => bool) public transferAgents;\n /**\n * Limit token transfer until the crowdsale is over.\n *\n */\n modifier canTransfer(address _sender) {\n if(!released) {\n if(!transferAgents[_sender]) {\n throw;\n }\n }\n _;\n }\n /**\n * Set the contract that can call release and make the token transferable.\n *\n * Design choice. Allow reset the release agent to fix fat finger mistakes.\n */\n function setReleaseAgent(address addr) onlyOwner inReleaseState(false) public {\n // We don't do interface check here as we might want to a normal wallet address to act as a release agent\n releaseAgent = addr;\n }\n /**\n * Owner can allow a particular address (a crowdsale contract) to transfer tokens despite the lock up period.\n */\n function setTransferAgent(address addr, bool state) onlyOwner inReleaseState(false) public {\n transferAgents[addr] = state;\n }\n /**\n * One way function to release the tokens to the wild.\n *\n * Can be called only from the release agent that is the final ICO contract. It is only called if the crowdsale has been success (first milestone reached).\n */\n function releaseTokenTransfer() public onlyReleaseAgent {\n released = true;\n }\n /** The function can be called only before or after the tokens have been releasesd */\n modifier inReleaseState(bool releaseState) {\n if(releaseState != released) {\n throw;\n }\n _;\n }\n /** The function can be called only by a whitelisted release agent. */\n modifier onlyReleaseAgent() {\n if(msg.sender != releaseAgent) {\n throw;\n }\n _;\n }\n function transfer(address _to, uint _value) canTransfer(msg.sender) returns (bool success) {\n // Call StandardToken.transfer()\n return super.transfer(_to, _value);\n }\n function transferFrom(address _from, address _to, uint _value) canTransfer(_from) returns (bool success) {\n // Call StandardToken.transferForm()\n return super.transferFrom(_from, _to, _value);\n }\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * Safe unsigned safe math.\n *\n * https://blog.aragon.one/library-driven-development-in-solidity-2bebcaf88736#.750gwtwli\n *\n * Originally from https://raw.githubusercontent.com/AragonOne/zeppelin-solidity/master/contracts/SafeMathLib.sol\n *\n * Maintained here until merged to mainline zeppelin-solidity.\n *\n */\nlibrary SafeMathLibExt {\n function times(uint a, uint b) returns (uint) {\n uint c = a * b;\n assert(a == 0 || c / a == b);\n return c;\n }\n function divides(uint a, uint b) returns (uint) {\n assert(b > 0);\n uint c = a / b;\n assert(a == b * c + a % b);\n return c;\n }\n function minus(uint a, uint b) returns (uint) {\n assert(b <= a);\n return a - b;\n }\n function plus(uint a, uint b) returns (uint) {\n uint c = a + b;\n assert(c>=a);\n return c;\n }\n}\n/**\n * A token that can increase its supply by another contract.\n *\n * This allows uncapped crowdsale by dynamically increasing the supply when money pours in.\n * Only mint agents, contracts whitelisted by owner, can mint new tokens.\n *\n */\ncontract MintableTokenExt is StandardToken, Ownable {\n using SafeMathLibExt for uint;\n bool public mintingFinished = false;\n /** List of agents that are allowed to create new tokens */\n mapping (address => bool) public mintAgents;\n event MintingAgentChanged(address addr, bool state );\n struct ReservedTokensData {\n uint inTokens;\n uint inPercentage;\n }\n mapping (address => ReservedTokensData) public reservedTokensList;\n address[] public reservedTokensDestinations;\n uint public reservedTokensDestinationsLen = 0;\n function setReservedTokensList(address addr, uint inTokens, uint inPercentage) onlyOwner {\n reservedTokensDestinations.push(addr);\n reservedTokensDestinationsLen++;\n reservedTokensList[addr] = ReservedTokensData({inTokens:inTokens, inPercentage:inPercentage});\n }\n function getReservedTokensListValInTokens(address addr) constant returns (uint inTokens) {\n return reservedTokensList[addr].inTokens;\n }\n function getReservedTokensListValInPercentage(address addr) constant returns (uint inPercentage) {\n return reservedTokensList[addr].inPercentage;\n }\n function setReservedTokensListMultiple(address[] addrs, uint[] inTokens, uint[] inPercentage) onlyOwner {\n for (uint iterator = 0; iterator < addrs.length; iterator++) {\n setReservedTokensList(addrs[iterator], inTokens[iterator], inPercentage[iterator]);\n }\n }\n /**\n * Create new tokens and allocate them to an address..\n *\n * Only callably by a crowdsale contract (mint agent).\n */\n function mint(address receiver, uint amount) onlyMintAgent canMint public {\n totalSupply = totalSupply.plus(amount);\n balances[receiver] = balances[receiver].plus(amount);\n // This will make the mint transaction apper in EtherScan.io\n // We can remove this after there is a standardized minting event\n Transfer(0, receiver, amount);\n }\n /**\n * Owner can allow a crowdsale contract to mint new tokens.\n */\n function setMintAgent(address addr, bool state) onlyOwner canMint public {\n mintAgents[addr] = state;\n MintingAgentChanged(addr, state);\n }\n modifier onlyMintAgent() {\n // Only crowdsale contracts are allowed to mint new tokens\n if(!mintAgents[msg.sender]) {\n throw;\n }\n _;\n }\n /** Make sure we are not done yet. */\n modifier canMint() {\n if(mintingFinished) throw;\n _;\n }\n}\n/**\n * A crowdsaled token.\n *\n * An ERC-20 token designed specifically for crowdsales with investor protection and further development path.\n *\n * - The token transfer() is disabled until the crowdsale is over\n * - The token contract gives an opt-in upgrade path to a new contract\n * - The same token can be part of several crowdsales through approve() mechanism\n * - The token can be capped (supply set in the constructor) or uncapped (crowdsale contract can mint new tokens)\n *\n */\ncontract CrowdsaleTokenExt is ReleasableToken, MintableTokenExt, UpgradeableToken {\n /** Name and symbol were updated. */\n event UpdatedTokenInformation(string newName, string newSymbol);\n string public name;\n string public symbol;\n uint public decimals;\n /* Minimum ammount of tokens every buyer can buy. */\n uint public minCap;\n /**\n * Construct the token.\n *\n * This token must be created through a team multisig wallet, so that it is owned by that wallet.\n *\n * @param _name Token name\n * @param _symbol Token symbol - should be all caps\n * @param _initialSupply How many tokens we start with\n * @param _decimals Number of decimal places\n * @param _mintable Are new tokens created over the crowdsale or do we distribute only the initial supply? Note that when the token becomes transferable the minting always ends.\n */\n function CrowdsaleTokenExt(string _name, string _symbol, uint _initialSupply, uint _decimals, bool _mintable, uint _globalMinCap)\n UpgradeableToken(msg.sender) {\n // Create any address, can be transferred\n // to team multisig via changeOwner(),\n // also remember to call setUpgradeMaster()\n owner = msg.sender;\n name = _name;\n symbol = _symbol;\n totalSupply = _initialSupply;\n decimals = _decimals;\n minCap = _globalMinCap;\n // Create initially all balance on the team multisig\n balances[owner] = totalSupply;\n if(totalSupply > 0) {\n Minted(owner, totalSupply);\n }\n // No more new supply allowed after the token creation\n if(!_mintable) {\n mintingFinished = true;\n if(totalSupply == 0) {\n throw; // Cannot create a token without supply and no minting\n }\n }\n }\n /**\n * When token is released to be transferable, enforce no new tokens can be created.\n */\n function releaseTokenTransfer() public onlyReleaseAgent {\n mintingFinished = true;\n super.releaseTokenTransfer();\n }\n /**\n * Allow upgrade agent functionality kick in only if the crowdsale was success.\n */\n function canUpgrade() public constant returns(bool) {\n return released && super.canUpgrade();\n }\n /**\n * Owner can update token information here.\n *\n * It is often useful to conceal the actual token association, until\n * the token operations, like central issuance or reissuance have been completed.\n *\n * This function allows the token owner to rename the token after the operations\n * have been completed and then point the audience to use the token contract.\n */\n function setTokenInformation(string _name, string _symbol) onlyOwner {\n name = _name;\n symbol = _symbol;\n UpdatedTokenInformation(name, symbol);\n }\n}", + "expected_bytecode": "606060405236156101e05763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166302f652a381146101e257806305d2035b1461020557806306fdde0314610229578063095ea7b3146102b957806318160ddd146102ec57806323b872dd1461030e57806329ff4f5314610347578063313ce56714610365578063338f43a0146103875780633fa615b0146103b557806340c10f19146103d757806342c1867b146103f8578063432146751461042857806345977d031461044b5780634eee966f1461046057806351ed17a4146104f55780635de4ccb01461052a5780635f412d4f14610556578063600440cb1461056857806370a08231146105945780637386f0a7146105c257806380c190cf146105f15780638444b3911461061f578063867c2857146106535780638da5cb5b1461068357806395d89b41146106af578063961325211461073f5780639738968c14610763578063a9059cbb14610787578063b4ffaece146107ba578063c33105171461087f578063c752ff62146108a1578063d1f276d3146108c3578063d7e7088a146108ef578063dd62ed3e1461090d578063eefa597b14610941578063f2fde38b14610965578063f30f850814610983578063ffeb7d75146109a7575bfe5b34156101ea57fe5b610203600160a060020a036004351660243515156109c5565b005b341561020d57fe5b610215610a28565b604080519115158252519081900360200190f35b341561023157fe5b610239610a31565b60408051602080825283518183015283519192839290830191850190808383821561027f575b80518252602083111561027f57601f19909201916020918201910161025f565b505050905090810190601f1680156102ab5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156102c157fe5b610215600160a060020a0360043516602435610abf565b604080519115158252519081900360200190f35b34156102f457fe5b6102fc610b66565b60408051918252519081900360200190f35b341561031657fe5b610215600160a060020a0360043581169060243516604435610b6c565b604080519115158252519081900360200190f35b341561034f57fe5b610203600160a060020a0360043516610bc4565b005b341561036d57fe5b6102fc610c2a565b60408051918252519081900360200190f35b341561038f57fe5b6102fc600160a060020a0360043516610c30565b60408051918252519081900360200190f35b34156103bd57fe5b6102fc610c4f565b60408051918252519081900360200190f35b34156103df57fe5b610203600160a060020a0360043516602435610c55565b005b341561040057fe5b610215600160a060020a0360043516610e1b565b604080519115158252519081900360200190f35b341561043057fe5b610203600160a060020a03600435166024351515610e30565b005b341561045357fe5b610203600435610ec4565b005b341561046857fe5b610203600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f89358b0180359182018390048302840183019094528083529799988101979196509182019450925082915084018382808284375094965061103495505050505050565b005b34156104fd57fe5b610511600160a060020a03600435166111a8565b6040805192835260208301919091528051918290030190f35b341561053257fe5b61053a6111c1565b60408051600160a060020a039092168252519081900360200190f35b341561055e57fe5b6102036111d0565b005b341561057057fe5b61053a611205565b60408051600160a060020a039092168252519081900360200190f35b341561059c57fe5b6102fc600160a060020a0360043516611214565b60408051918252519081900360200190f35b34156105ca57fe5b61053a600435611233565b60408051600160a060020a039092168252519081900360200190f35b34156105f957fe5b6102fc600160a060020a0360043516611265565b60408051918252519081900360200190f35b341561062757fe5b61062f611287565b6040518082600481111561063f57fe5b60ff16815260200191505060405180910390f35b341561065b57fe5b610215600160a060020a03600435166112d4565b604080519115158252519081900360200190f35b341561068b57fe5b61053a6112e9565b60408051600160a060020a039092168252519081900360200190f35b34156106b757fe5b6102396112f8565b60408051602080825283518183015283519192839290830191850190808383821561027f575b80518252602083111561027f57601f19909201916020918201910161025f565b505050905090810190601f1680156102ab5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561074757fe5b610215611386565b604080519115158252519081900360200190f35b341561076b57fe5b610215611396565b604080519115158252519081900360200190f35b341561078f57fe5b610215600160a060020a03600435166024356113bc565b604080519115158252519081900360200190f35b34156107c257fe5b610203600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750506040805187358901803560208181028481018201909552818452989a99890198929750908201955093508392508501908490808284375094965061141295505050505050565b005b341561088757fe5b6102fc61149f565b60408051918252519081900360200190f35b34156108a957fe5b6102fc6114a5565b60408051918252519081900360200190f35b34156108cb57fe5b61053a6114ab565b60408051600160a060020a039092168252519081900360200190f35b34156108f757fe5b610203600160a060020a03600435166114ba565b005b341561091557fe5b6102fc600160a060020a0360043581169060243516611697565b60408051918252519081900360200190f35b341561094957fe5b6102156116c4565b604080519115158252519081900360200190f35b341561096d57fe5b610203600160a060020a03600435166116ca565b005b341561098b57fe5b610203600160a060020a0360043516602435604435611763565b005b34156109af57fe5b610203600160a060020a03600435166117fe565b005b60035433600160a060020a039081169116146109e15760006000fd5b60045460009060a060020a900460ff16156109fc5760006000fd5b600160a060020a0383166000908152600560205260409020805460ff19168315151790555b5b505b5050565b60065460ff1681565b600e805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ab75780601f10610a8c57610100808354040283529160200191610ab7565b820191906000526020600020905b815481529060010190602001808311610a9a57829003601f168201915b505050505081565b60008115801590610af45750600160a060020a0333811660009081526002602090815260408083209387168352929052205415155b15610aff5760006000fd5b600160a060020a03338116600081815260026020908152604080832094881680845294825291829020869055815186815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a35060015b92915050565b60005481565b600454600090849060a060020a900460ff161515610bac57600160a060020a03811660009081526005602052604090205460ff161515610bac5760006000fd5b5b610bb885858561185c565b91505b5b509392505050565b60035433600160a060020a03908116911614610be05760006000fd5b60045460009060a060020a900460ff1615610bfb5760006000fd5b6004805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0384161790555b5b505b50565b60105481565b600160a060020a0381166000908152600860205260409020545b919050565b60115481565b600160a060020a03331660009081526007602052604090205460ff161515610c7d5760006000fd5b60065460ff1615610c8e5760006000fd5b6000547354ca5a7c536dbed5897b78d30a93dcd0e46fbdac6366098d4f9091836000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808381526020018281526020019250505060206040518083038186803b1515610d0a57fe5b6102c65a03f41515610d1857fe5b50506040805180516000908155600160a060020a038616815260016020908152838220549281019190915282517f66098d4f00000000000000000000000000000000000000000000000000000000815260048101929092526024820185905291517354ca5a7c536dbed5897b78d30a93dcd0e46fbdac93506366098d4f92604480840193919291829003018186803b1515610daf57fe5b6102c65a03f41515610dbd57fe5b5050604080518051600160a060020a0386166000818152600160209081528582209390935586845293519094507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35b5b5b5050565b60076020526000908152604090205460ff1681565b60035433600160a060020a03908116911614610e4c5760006000fd5b60065460ff1615610e5d5760006000fd5b600160a060020a038216600081815260076020908152604091829020805460ff191685151590811790915582519384529083015280517f4b0adf6c802794c7dde28a08a4e07131abcff3bf9603cd71f14f90bec7865efa9281900390910190a15b5b5b5050565b6000610ece611287565b905060035b816004811115610edf57fe5b1480610ef7575060045b816004811115610ef557fe5b145b1515610f035760006000fd5b811515610f105760006000fd5b600160a060020a033316600090815260016020526040902054610f33908361195f565b600160a060020a03331660009081526001602052604081209190915554610f5a908361195f565b600055600d54610f6a9083611976565b600d55600c54604080517f753e88e5000000000000000000000000000000000000000000000000000000008152600160a060020a033381166004830152602482018690529151919092169163753e88e591604480830192600092919082900301818387803b1515610fd757fe5b6102c65a03f11515610fe557fe5b5050600c54604080518581529051600160a060020a03928316935033909216917f7e5c344a8141a805725cb476f76c6953b842222b967edd1f78ddb6e8b3f397ac9181900360200190a35b5050565b60035433600160a060020a039081169116146110505760006000fd5b815161106390600e906020850190611a9c565b50805161107790600f906020840190611a9c565b5060408051818152600e8054600260001961010060018416150201909116049282018390527fd131ab1e6f279deea74e13a18477e13e2107deb6dc8ae955648948be5841fb46929091600f918190602082019060608301908690801561111e5780601f106110f35761010080835404028352916020019161111e565b820191906000526020600020905b81548152906001019060200180831161110157829003601f168201915b50508381038252845460026000196101006001841615020190911604808252602090910190859080156111925780601f1061116757610100808354040283529160200191611192565b820191906000526020600020905b81548152906001019060200180831161117557829003601f168201915b505094505050505060405180910390a15b5b5050565b6008602052600090815260409020805460019091015482565b600c54600160a060020a031681565b60045433600160a060020a039081169116146111ec5760006000fd5b6006805460ff1916600117905561120161199e565b5b5b565b600b54600160a060020a031681565b600160a060020a0381166000908152600160205260409020545b919050565b600980548290811061124157fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b600160a060020a0381166000908152600860205260409020600101545b919050565b6000611291611396565b151561129f575060016112ce565b600c54600160a060020a031615156112b9575060026112ce565b600d5415156112ca575060036112ce565b5060045b5b5b5b90565b60056020526000908152604090205460ff1681565b600354600160a060020a031681565b600f805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ab75780601f10610a8c57610100808354040283529160200191610ab7565b820191906000526020600020905b815481529060010190602001808311610a9a57829003601f168201915b505050505081565b60045460a060020a900460ff1681565b60045460009060a060020a900460ff1680156113b557506113b56116c4565b5b90505b90565b600454600090339060a060020a900460ff1615156113fc57600160a060020a03811660009081526005602052604090205460ff1615156113fc5760006000fd5b5b61140784846119e8565b91505b5b5092915050565b60035460009033600160a060020a039081169116146114315760006000fd5b5060005b83518110156114975761148e848281518110151561144f57fe5b90602001906020020151848381518110151561146757fe5b90602001906020020151848481518110151561147f57fe5b90602001906020020151611763565b5b600101611435565b5b5b50505050565b600a5481565b600d5481565b600454600160a060020a031681565b6114c2611396565b15156114ce5760006000fd5b600160a060020a03811615156114e45760006000fd5b600b5433600160a060020a039081169116146115005760006000fd5b60045b61150b611287565b600481111561151657fe5b14156115225760006000fd5b600c805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a038381169190911791829055604080516000602091820181905282517f61d3d7a6000000000000000000000000000000000000000000000000000000008152925194909316936361d3d7a6936004808501948390030190829087803b15156115a857fe5b6102c65a03f115156115b657fe5b505060405151151590506115ca5760006000fd5b60008054600c5460408051602090810185905281517f4b2ba0dd00000000000000000000000000000000000000000000000000000000815291519394600160a060020a0390931693634b2ba0dd936004808501948390030190829087803b151561163057fe5b6102c65a03f1151561163e57fe5b5050604051519190911490506116545760006000fd5b600c5460408051600160a060020a039092168252517f7845d5aa74cc410e35571258d954f23b82276e160fe8c188fa80566580f279cc9181900360200190a15b50565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b92915050565b60015b90565b60035433600160a060020a039081169116146116e65760006000fd5b600160a060020a03811615156116fc5760006000fd5b600354604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a36003805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b60035433600160a060020a0390811691161461177f5760006000fd5b60098054600181016117918382611b1b565b916000526020600020900160005b8154600160a060020a038088166101009390930a83810291021990911617909155600a80546001908101909155604080518082018252868152602080820187815260009586526008909152919093209251835551910155505b5b505050565b600160a060020a03811615156118145760006000fd5b600b5433600160a060020a039081169116146118305760006000fd5b600b805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b50565b600160a060020a03808416600090815260026020908152604080832033851684528252808320549386168352600190915281205490919061189d9084611976565b600160a060020a0380861660009081526001602052604080822093909355908716815220546118cc908461195f565b600160a060020a0386166000908152600160205260409020556118ef818461195f565b600160a060020a038087166000818152600260209081526040808320338616845282529182902094909455805187815290519288169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3600191505b509392505050565b60008282111561196b57fe5b508082035b92915050565b600082820183811080159061198b5750828110155b151561199357fe5b8091505b5092915050565b60045433600160a060020a039081169116146119ba5760006000fd5b6004805474ff0000000000000000000000000000000000000000191660a060020a1790555b5b565b60015b90565b600160a060020a033316600090815260016020526040812054611a0b908361195f565b600160a060020a033381166000908152600160205260408082209390935590851681522054611a3a9083611976565b600160a060020a038085166000818152600160209081526040918290209490945580518681529051919333909316927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a35060015b92915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611add57805160ff1916838001178555611b0a565b82800160010185558215611b0a579182015b82811115611b0a578251825591602001919060010190611aef565b5b50611b17929150611b45565b5090565b815481835581811511610a2157600083815260209020610a21918101908301611b45565b5b505050565b6112ce91905b80821115611b175760008155600101611b4b565b5090565b905600a165627a7a72305820c38ce552da1339b41e837cc46418755767ab24eb6b08726516f1e03f7b96fca9002900000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000085570666972696e6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035546520000000000000000000000000000000000000000000000000000000000", + "external_libraries": { + "SafeMathLibExt": "0x54ca5a7c536dbed5897b78d30a93dcd0e46fbdac" + }, + "name": "CrowdsaleTokenExt", + "optimize": true + } + ] + \ No newline at end of file