diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bb5799000..a7eab10a3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ ## Current ### Features - -- [#1895](https://github.com/poanetwork/blockscout/pull/1874) - add changes to poa theme and poa logo +- [#1907](https://github.com/poanetwork/blockscout/pull/1907) - dropdown color bug fix (lukso theme) and tooltip color bug fix +- [#1903](https://github.com/poanetwork/blockscout/pull/1903) - added rsk theme and rsk logo +- [#1895](https://github.com/poanetwork/blockscout/pull/1895) - add changes to poa theme and poa logo - [#1812](https://github.com/poanetwork/blockscout/pull/1812) - add pagination to addresses page - [#1874](https://github.com/poanetwork/blockscout/pull/1874) - add changes to ethereum theme and ethereum logo - [#1815](https://github.com/poanetwork/blockscout/pull/1815) - able to search without prefix "0x" @@ -25,6 +26,7 @@ - [#1896](https://github.com/poanetwork/blockscout/pull/1896) - re-query tokens in top nav automplete - [#1881](https://github.com/poanetwork/blockscout/pull/1881) - fix: store solc versions locally for performance - [#1904](https://github.com/poanetwork/blockscout/pull/1904) - fix `BLOCK_COUNT_CACHE_TTL` env var type +- [#1898](https://github.com/poanetwork/blockscout/pull/1898) - check if the constructor has arguments before verifying constructor arguments ### Chore diff --git a/README.md b/README.md index 289a3d35ed..9755475dbe 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ Currently available block explorers (i.e. Etherscan and Etherchain) are closed s * [SpringChain](https://explorer.springrole.com/) * [PIRL](http://pirl.es/) * [Petrichor](https://explorer.petrichor-dev.com/) +* [Ether-1](https://blocks.ether1.wattpool.net/) ### Visual Interface diff --git a/apps/block_scout_web/assets/css/components/_tooltip.scss b/apps/block_scout_web/assets/css/components/_tooltip.scss index 1cd7797785..4c845a7c1c 100644 --- a/apps/block_scout_web/assets/css/components/_tooltip.scss +++ b/apps/block_scout_web/assets/css/components/_tooltip.scss @@ -14,5 +14,6 @@ $tooltip-color: #fff !default; .arrow::before { border-top-color: $tooltip-background-color; + border-bottom-color: $tooltip-background-color; } } diff --git a/apps/block_scout_web/assets/css/theme/_lukso_variables.scss b/apps/block_scout_web/assets/css/theme/_lukso_variables.scss index a09049e7c8..c1d8d630f9 100644 --- a/apps/block_scout_web/assets/css/theme/_lukso_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_lukso_variables.scss @@ -12,7 +12,7 @@ $dashboard-stats-item-value-color: $primary; $dashboard-stats-item-border-color: $primary; $header-links-color-active: #333; - +.dropdown-item:hover, .dropdown-item:focus { background-color: $primary !important; } $tile-type-block-color: $secondary; $navbar-logo-height: 18px; diff --git a/apps/block_scout_web/assets/css/theme/_rsk_variables.scss b/apps/block_scout_web/assets/css/theme/_rsk_variables.scss new file mode 100644 index 0000000000..c357f0f571 --- /dev/null +++ b/apps/block_scout_web/assets/css/theme/_rsk_variables.scss @@ -0,0 +1,50 @@ +// general +$primary: #101f25; +$secondary: #27ac8d; +$tertiary: #e39a54; +$additional-font: #a1ded1; + +// footer +$footer-background-color: $primary; +$footer-title-color: #fff; +$footer-text-color: $additional-font; +$footer-item-disc-color: $secondary; +.footer-logo { filter: brightness(0) invert(1); } + +// dashboard +$dashboard-line-color-price: $tertiary; // price left border + +$dashboard-banner-chart-legend-value-color: $additional-font; // chart labels + +$dashboard-stats-item-value-color: $additional-font; // stat values + +$dashboard-stats-item-border-color: $secondary; // stat border + +$dashboard-banner-gradient-start: $primary; // gradient begin + +$dashboard-banner-gradient-end: lighten($primary, 5); // gradient end + +$dashboard-banner-network-plain-container-background-color: #1a323b; // stats bg + + +// navigation +.navbar { box-shadow: 0px 0px 30px 0px rgba(21, 53, 80, 0.12); } // header shadow +$header-icon-border-color-hover: $secondary; // top border on hover +$header-icon-color-hover: $secondary; // nav icon on hover +.dropdown-item:hover, .dropdown-item:focus { background-color: $secondary !important; } // dropdown item on hover + +// buttons +$btn-line-bg: #fff; // button bg +$btn-line-color: $secondary; // button border and font color && hover bg color +$btn-copy-color: $secondary; // btn copy +$btn-qr-color: $secondary; // btn qr-code + +//links & tile +.tile a { color: $secondary !important; } // links color for badges +.tile-type-block { + border-left: 4px solid $secondary; +} // tab active bg + +// card +$card-background-1: $secondary; +$card-tab-active: $secondary; \ No newline at end of file diff --git a/apps/block_scout_web/assets/static/images/rsk_logo.svg b/apps/block_scout_web/assets/static/images/rsk_logo.svg new file mode 100644 index 0000000000..8502c921e5 --- /dev/null +++ b/apps/block_scout_web/assets/static/images/rsk_logo.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/explorer/lib/explorer/smart_contract/verifier.ex b/apps/explorer/lib/explorer/smart_contract/verifier.ex index 0fc9f6b21b..4b521fba35 100644 --- a/apps/explorer/lib/explorer/smart_contract/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/verifier.ex @@ -74,7 +74,7 @@ defmodule Explorer.SmartContract.Verifier do generated_bytecode != blockchain_bytecode_without_whisper -> {:error, :generated_bytecode} - !ConstructorArguments.verify(address_hash, arguments_data) -> + has_constructor_with_params?(abi) && !ConstructorArguments.verify(address_hash, arguments_data) -> {:error, :constructor_arguments} true -> @@ -111,4 +111,8 @@ defmodule Explorer.SmartContract.Verifier do prev_version end end + + defp has_constructor_with_params?(abi) do + Enum.any?(abi, fn el -> el["type"] == "constructor" && el["inputs"] != [] end) + end end diff --git a/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs b/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs index 79bbb62f70..57f15577ac 100644 --- a/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs +++ b/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs @@ -173,6 +173,101 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do assert {:error, :compilation} = response end + + test "returns constructor in abi" do + code = """ + pragma solidity ^0.4.22; + + contract OwnedToken { + // TokenCreator is a contract type that is defined below. + // It is fine to reference it as long as it is not used + // to create a new contract. + TokenCreator creator; + address owner; + bytes32 name; + + // This is the constructor which registers the + // creator and the assigned name. + constructor(bytes32 _name) public { + // State variables are accessed via their name + // and not via e.g. this.owner. This also applies + // to functions and especially in the constructors, + // you can only call them like that ("internally"), + // because the contract itself does not exist yet. + owner = msg.sender; + // We do an explicit type conversion from `address` + // to `TokenCreator` and assume that the type of + // the calling contract is TokenCreator, there is + // no real way to check that. + creator = TokenCreator(msg.sender); + name = _name; + } + + function changeName(bytes32 newName) public { + // Only the creator can alter the name -- + // the comparison is possible since contracts + // are implicitly convertible to addresses. + if (msg.sender == address(creator)) + name = newName; + } + + function transfer(address newOwner) public { + // Only the current owner can transfer the token. + if (msg.sender != owner) return; + // We also want to ask the creator if the transfer + // is fine. Note that this calls a function of the + // contract defined below. If the call fails (e.g. + // due to out-of-gas), the execution here stops + // immediately. + if (creator.isTokenTransferOK(owner, newOwner)) + owner = newOwner; + } + } + + contract TokenCreator { + function createToken(bytes32 name) + public + returns (OwnedToken tokenAddress) + { + // Create a new Token contract and return its address. + // From the JavaScript side, the return type is simply + // `address`, as this is the closest type available in + // the ABI. + return new OwnedToken(name); + } + + function changeName(OwnedToken tokenAddress, bytes32 name) public { + // Again, the external type of `tokenAddress` is + // simply `address`. + tokenAddress.changeName(name); + } + + function isTokenTransferOK(address currentOwner, address newOwner) + public + view + returns (bool ok) + { + // Check some arbitrary condition. + address tokenAddress = msg.sender; + return (keccak256(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff); + } + } + """ + + name = "OwnedToken" + compiler_version = "v0.4.22+commit.4cb486ee" + + {:ok, %{"abi" => abi}} = + CodeCompiler.run( + name: name, + compiler_version: compiler_version, + code: code, + evm_version: "byzantium", + optimize: true + ) + + assert Enum.any?(abi, fn el -> el["type"] == "constructor" end) + end end describe "get_contract_info/1" do diff --git a/apps/explorer/test/explorer/smart_contract/verifier_test.exs b/apps/explorer/test/explorer/smart_contract/verifier_test.exs index 631c15695e..1e8301a90c 100644 --- a/apps/explorer/test/explorer/smart_contract/verifier_test.exs +++ b/apps/explorer/test/explorer/smart_contract/verifier_test.exs @@ -117,31 +117,6 @@ defmodule Explorer.SmartContract.VerifierTest do assert abi != nil end - test "returns error when constructor arguments do not match", %{ - contract_code_info: contract_code_info - } do - contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode) - - constructor_arguments = "0102030405" - - params = %{ - "contract_source_code" => contract_code_info.source_code, - "compiler_version" => contract_code_info.version, - "name" => contract_code_info.name, - "optimization" => contract_code_info.optimized, - "constructor_arguments" => constructor_arguments - } - - :transaction - |> insert( - created_contract_address_hash: contract_address.hash, - input: Verifier.extract_bytecode(contract_code_info.bytecode) <> "010203" - ) - |> with_block() - - assert {:error, :constructor_arguments} = Verifier.evaluate_authenticity(contract_address.hash, params) - end - test "returns error when bytecode doesn't match", %{contract_code_info: contract_code_info} do contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)