Merge pull request #4924 from blockscout/np-add-security-check-for-bytecode

Add daily bytecode verifcation to prevent metamorphic contracts vulnerablity
pull/4983/head
Victor Baranov 3 years ago committed by GitHub
commit 8b77afb1e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .dialyzer-ignore
  2. 1
      CHANGELOG.md
  3. 3
      apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex
  4. 4
      apps/block_scout_web/lib/block_scout_web/templates/common_components/_changed_bytecode_warning.html.eex
  5. 6
      apps/block_scout_web/lib/block_scout_web/templates/smart_contract/_functions.html.eex
  6. 85
      apps/block_scout_web/priv/gettext/default.pot
  7. 85
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  8. 6
      apps/block_scout_web/test/block_scout_web/controllers/address_read_contract_controller_test.exs
  9. 6
      apps/block_scout_web/test/block_scout_web/controllers/address_read_proxy_controller_test.exs
  10. 6
      apps/block_scout_web/test/block_scout_web/controllers/address_write_contract_controller_test.exs
  11. 6
      apps/block_scout_web/test/block_scout_web/controllers/address_write_proxy_controller_test.exs
  12. 16
      apps/block_scout_web/test/block_scout_web/controllers/smart_contract_controller_test.exs
  13. 45
      apps/explorer/lib/explorer/chain.ex
  14. 17
      apps/explorer/lib/explorer/chain/smart_contract.ex
  15. 13
      apps/explorer/priv/repo/migrations/20211115164817_add_check_for_bytecode_actuality.exs
  16. 14
      apps/explorer/test/explorer/chain/log_test.exs

@ -23,8 +23,8 @@ lib/indexer/fetcher/token_total_supply_on_demand.ex:16
lib/explorer/exchange_rates/source.ex:110
lib/explorer/exchange_rates/source.ex:113
lib/explorer/smart_contract/solidity/verifier.ex:162
lib/block_scout_web/templates/address_contract/index.html.eex:159
lib/block_scout_web/templates/address_contract/index.html.eex:196
lib/block_scout_web/templates/address_contract/index.html.eex:162
lib/block_scout_web/templates/address_contract/index.html.eex:199
lib/explorer/staking/stake_snapshotting.ex:15: Function do_snapshotting/7 has no local return
lib/explorer/staking/stake_snapshotting.ex:147
lib/explorer/third_party_integrations/sourcify.ex:70

@ -1,6 +1,7 @@
## Current
### Features
- [#4924](https://github.com/blockscout/blockscout/pull/4924) - Add daily bytecode verifcation to prevent metamorphic contracts vulnerablity
- [#4908](https://github.com/blockscout/blockscout/pull/4908) - Add verification via standard JSON input
- [#5004](https://github.com/blockscout/blockscout/pull/5004) - Add ability to set up a separate DB endpoint for the API endpoints
- [#4989](https://github.com/blockscout/blockscout/pull/4989), [#4991](https://github.com/blockscout/blockscout/pull/4991) - Bridged tokens list API endpoint

@ -31,6 +31,9 @@
<% end %>
<% end %>
<% end %>
<%= if smart_contract_verified && @address.smart_contract.is_changed_bytecode do %>
<%= render BlockScoutWeb.CommonComponentsView, "_changed_bytecode_warning.html" %>
<% end %>
<%= if smart_contract_verified || (!smart_contract_verified && metadata_for_verification) do %>
<% target_contract = if smart_contract_verified, do: @address.smart_contract, else: metadata_for_verification %>
<%= if @address.smart_contract.partially_verified && smart_contract_verified do %>

@ -0,0 +1,4 @@
<div class="mb-4" style="display: inline-table; font-size: 14px; background: bisque; padding: 10px; border-radius: 5px;">
<%= render BlockScoutWeb.CommonComponentsView, "_info.html" %>
<span> <%= gettext("Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.") %></span>
</div>

@ -1,6 +1,7 @@
<% minimal_proxy_template = Chain.get_minimal_proxy_template(@address.hash) %>
<% metadata_for_verification = minimal_proxy_template || Chain.get_address_verified_twin_contract(@address.hash).verified_contract %>
<%= unless BlockScoutWeb.AddressView.smart_contract_verified?(@address) do %>
<% smart_contract_verified = BlockScoutWeb.AddressView.smart_contract_verified?(@address) %>
<%= unless smart_contract_verified do %>
<%= if metadata_for_verification do %>
<%= if minimal_proxy_template do %>
<%= render BlockScoutWeb.CommonComponentsView, "_minimal_proxy_pattern.html", address_hash: metadata_for_verification.address_hash, conn: @conn %>
@ -17,6 +18,9 @@
<% end %>
<% end %>
<% end %>
<%= if smart_contract_verified && @address.smart_contract.is_changed_bytecode do %>
<%= render BlockScoutWeb.CommonComponentsView, "_changed_bytecode_warning.html" %>
<% end %>
<%= if @action == "write" or (@read_functions_required_wallet && @read_functions_required_wallet != []) do %>
<%= render BlockScoutWeb.SmartContractView, "_connect_container.html" %>
<% end %>

@ -215,7 +215,7 @@ msgid "All"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:12
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:13
msgid "All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with"
msgstr ""
@ -582,7 +582,7 @@ msgid "Compiler"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:62
#: lib/block_scout_web/templates/address_contract/index.html.eex:65
msgid "Compiler version"
msgstr ""
@ -633,7 +633,7 @@ msgid "Connection Lost, click to load newer validations"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:87
#: lib/block_scout_web/templates/address_contract/index.html.eex:90
msgid "Constructor Arguments"
msgstr ""
@ -643,7 +643,7 @@ msgid "Contract"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:123
#: lib/block_scout_web/templates/address_contract/index.html.eex:126
msgid "Contract ABI"
msgstr ""
@ -673,8 +673,8 @@ msgid "Contract Creation"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:139
#: lib/block_scout_web/templates/address_contract/index.html.eex:154
#: lib/block_scout_web/templates/address_contract/index.html.eex:142
#: lib/block_scout_web/templates/address_contract/index.html.eex:157
msgid "Contract Creation Code"
msgstr ""
@ -692,22 +692,22 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:25
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:10
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:11
msgid "Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:54
#: lib/block_scout_web/templates/address_contract/index.html.eex:57
msgid "Contract name:"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:97
#: lib/block_scout_web/templates/address_contract/index.html.eex:100
msgid "Contract source code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:145
#: lib/block_scout_web/templates/address_contract/index.html.eex:148
msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified."
msgstr ""
@ -717,7 +717,7 @@ msgid "Contribute"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:125
#: lib/block_scout_web/templates/address_contract/index.html.eex:128
msgid "Copy ABI"
msgstr ""
@ -730,8 +730,8 @@ msgid "Copy Address"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:141
#: lib/block_scout_web/templates/address_contract/index.html.eex:157
#: lib/block_scout_web/templates/address_contract/index.html.eex:144
#: lib/block_scout_web/templates/address_contract/index.html.eex:160
msgid "Copy Contract Creation Code"
msgstr ""
@ -741,8 +741,8 @@ msgid "Copy Decompiled Contract Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:184
#: lib/block_scout_web/templates/address_contract/index.html.eex:194
#: lib/block_scout_web/templates/address_contract/index.html.eex:187
#: lib/block_scout_web/templates/address_contract/index.html.eex:197
msgid "Copy Deployed ByteCode"
msgstr ""
@ -776,8 +776,8 @@ msgid "Copy Raw Trace"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:99
#: lib/block_scout_web/templates/address_contract/index.html.eex:112
#: lib/block_scout_web/templates/address_contract/index.html.eex:102
#: lib/block_scout_web/templates/address_contract/index.html.eex:115
msgid "Copy Source Code"
msgstr ""
@ -947,8 +947,8 @@ msgid "Delegators’ Staked Amount"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:182
#: lib/block_scout_web/templates/address_contract/index.html.eex:190
#: lib/block_scout_web/templates/address_contract/index.html.eex:185
#: lib/block_scout_web/templates/address_contract/index.html.eex:193
msgid "Deployed ByteCode"
msgstr ""
@ -971,7 +971,7 @@ msgid "Difficulty"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:146
#: lib/block_scout_web/templates/address_contract/index.html.eex:149
msgid "Displaying the init data provided of the creating transaction."
msgstr ""
@ -1017,8 +1017,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/overview.html.eex:1
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:89 lib/block_scout_web/templates/smart_contract/_functions.html.eex:89
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:128
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:93 lib/block_scout_web/templates/smart_contract/_functions.html.eex:93
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:132
msgid "ETH"
msgstr ""
@ -1028,7 +1028,7 @@ msgid "ETH RPC API Documentation"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:73
#: lib/block_scout_web/templates/address_contract/index.html.eex:76
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:40
msgid "EVM Version"
msgstr ""
@ -1138,7 +1138,7 @@ msgid "Export Data"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:225
#: lib/block_scout_web/templates/address_contract/index.html.eex:228
msgid "External libraries"
msgstr ""
@ -1706,12 +1706,12 @@ msgid "OUT"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:58
#: lib/block_scout_web/templates/address_contract/index.html.eex:61
msgid "Optimization enabled"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:67
#: lib/block_scout_web/templates/address_contract/index.html.eex:70
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:72
msgid "Optimization runs"
msgstr ""
@ -1864,7 +1864,7 @@ msgid "QR Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:94
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:98
msgid "Query"
msgstr ""
@ -2265,7 +2265,7 @@ msgid "The block height of a particular block is defined as the number of blocks
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:37
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:41
msgid "The fallback function is executed on a call to the contract if none of the other functions match the given function signature, or if no data was supplied at all and there is no receive Ether function. The fallback function always receives data, but in order to also receive Ether it must be marked payable."
msgstr ""
@ -2315,7 +2315,7 @@ msgid "The percentage of stake in a single pool relative to the total amount sta
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:39
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:43
msgid "The receive function is executed on a call to the contract with empty calldata. This is the function that is executed on plain Ether transfers (e.g. via .send() or .transfer()). If no such function exists, but a payable fallback function exists, the fallback function will be called on a plain Ether transfer. If neither a receive Ether nor a payable fallback function is present, the contract cannot receive Ether through regular transactions and throws an exception."
msgstr ""
@ -2467,12 +2467,12 @@ msgid "This block has not been processed yet."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:38
#: lib/block_scout_web/templates/address_contract/index.html.eex:41
msgid "This contract has been partially verified via Sourcify."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:42
#: lib/block_scout_web/templates/address_contract/index.html.eex:45
msgid "This contract has been verified via Sourcify."
msgstr ""
@ -2911,15 +2911,15 @@ msgid "Value sent in the native token (and USD) if applicable."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:79
#: lib/block_scout_web/templates/address_contract/index.html.eex:82
msgid "Verified at"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:27
#: lib/block_scout_web/templates/address_contract/index.html.eex:29 lib/block_scout_web/templates/address_contract/index.html.eex:161
#: lib/block_scout_web/templates/address_contract/index.html.eex:167 lib/block_scout_web/templates/address_contract/index.html.eex:198
#: lib/block_scout_web/templates/address_contract/index.html.eex:204 lib/block_scout_web/templates/smart_contract/_functions.html.eex:13
#: lib/block_scout_web/templates/address_contract/index.html.eex:29 lib/block_scout_web/templates/address_contract/index.html.eex:164
#: lib/block_scout_web/templates/address_contract/index.html.eex:170 lib/block_scout_web/templates/address_contract/index.html.eex:201
#: lib/block_scout_web/templates/address_contract/index.html.eex:207 lib/block_scout_web/templates/smart_contract/_functions.html.eex:14
msgid "Verify & Publish"
msgstr ""
@ -3004,7 +3004,7 @@ msgid "Vyper contract"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:127
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:131
msgid "WEI"
msgstr ""
@ -3018,6 +3018,11 @@ msgstr ""
msgid "Wallet addresses"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/common_components/_changed_bytecode_warning.html.eex:3
msgid "Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/stakes/_stakes_modal_claim_reward_content.html.eex:2
msgid "We found the following pools you can claim reward from:"
@ -3054,7 +3059,7 @@ msgid "Working Stake Amount"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:94
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:98
msgid "Write"
msgstr ""
@ -3184,7 +3189,7 @@ msgid "custom RPC"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:37
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:41
msgid "fallback"
msgstr ""
@ -3220,7 +3225,7 @@ msgid "of"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:15
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:16
msgid "page"
msgstr ""
@ -3230,7 +3235,7 @@ msgid "pool owner"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:39
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:43
msgid "receive"
msgstr ""

@ -215,7 +215,7 @@ msgid "All"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:12
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:13
msgid "All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with"
msgstr ""
@ -582,7 +582,7 @@ msgid "Compiler"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:62
#: lib/block_scout_web/templates/address_contract/index.html.eex:65
msgid "Compiler version"
msgstr ""
@ -633,7 +633,7 @@ msgid "Connection Lost, click to load newer validations"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:87
#: lib/block_scout_web/templates/address_contract/index.html.eex:90
msgid "Constructor Arguments"
msgstr ""
@ -643,7 +643,7 @@ msgid "Contract"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:123
#: lib/block_scout_web/templates/address_contract/index.html.eex:126
msgid "Contract ABI"
msgstr ""
@ -673,8 +673,8 @@ msgid "Contract Creation"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:139
#: lib/block_scout_web/templates/address_contract/index.html.eex:154
#: lib/block_scout_web/templates/address_contract/index.html.eex:142
#: lib/block_scout_web/templates/address_contract/index.html.eex:157
msgid "Contract Creation Code"
msgstr ""
@ -692,22 +692,22 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:25
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:10
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:11
msgid "Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:54
#: lib/block_scout_web/templates/address_contract/index.html.eex:57
msgid "Contract name:"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:97
#: lib/block_scout_web/templates/address_contract/index.html.eex:100
msgid "Contract source code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:145
#: lib/block_scout_web/templates/address_contract/index.html.eex:148
msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified."
msgstr ""
@ -717,7 +717,7 @@ msgid "Contribute"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:125
#: lib/block_scout_web/templates/address_contract/index.html.eex:128
msgid "Copy ABI"
msgstr ""
@ -730,8 +730,8 @@ msgid "Copy Address"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:141
#: lib/block_scout_web/templates/address_contract/index.html.eex:157
#: lib/block_scout_web/templates/address_contract/index.html.eex:144
#: lib/block_scout_web/templates/address_contract/index.html.eex:160
msgid "Copy Contract Creation Code"
msgstr ""
@ -741,8 +741,8 @@ msgid "Copy Decompiled Contract Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:184
#: lib/block_scout_web/templates/address_contract/index.html.eex:194
#: lib/block_scout_web/templates/address_contract/index.html.eex:187
#: lib/block_scout_web/templates/address_contract/index.html.eex:197
msgid "Copy Deployed ByteCode"
msgstr ""
@ -776,8 +776,8 @@ msgid "Copy Raw Trace"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:99
#: lib/block_scout_web/templates/address_contract/index.html.eex:112
#: lib/block_scout_web/templates/address_contract/index.html.eex:102
#: lib/block_scout_web/templates/address_contract/index.html.eex:115
msgid "Copy Source Code"
msgstr ""
@ -947,8 +947,8 @@ msgid "Delegators’ Staked Amount"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:182
#: lib/block_scout_web/templates/address_contract/index.html.eex:190
#: lib/block_scout_web/templates/address_contract/index.html.eex:185
#: lib/block_scout_web/templates/address_contract/index.html.eex:193
msgid "Deployed ByteCode"
msgstr ""
@ -971,7 +971,7 @@ msgid "Difficulty"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:146
#: lib/block_scout_web/templates/address_contract/index.html.eex:149
msgid "Displaying the init data provided of the creating transaction."
msgstr ""
@ -1017,8 +1017,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/overview.html.eex:1
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:89 lib/block_scout_web/templates/smart_contract/_functions.html.eex:89
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:128
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:93 lib/block_scout_web/templates/smart_contract/_functions.html.eex:93
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:132
msgid "ETH"
msgstr ""
@ -1028,7 +1028,7 @@ msgid "ETH RPC API Documentation"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:73
#: lib/block_scout_web/templates/address_contract/index.html.eex:76
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:40
msgid "EVM Version"
msgstr ""
@ -1138,7 +1138,7 @@ msgid "Export Data"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:225
#: lib/block_scout_web/templates/address_contract/index.html.eex:228
msgid "External libraries"
msgstr ""
@ -1706,12 +1706,12 @@ msgid "OUT"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:58
#: lib/block_scout_web/templates/address_contract/index.html.eex:61
msgid "Optimization enabled"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:67
#: lib/block_scout_web/templates/address_contract/index.html.eex:70
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:72
msgid "Optimization runs"
msgstr ""
@ -1864,7 +1864,7 @@ msgid "QR Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:94
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:98
msgid "Query"
msgstr ""
@ -2265,7 +2265,7 @@ msgid "The block height of a particular block is defined as the number of blocks
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:37
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:41
msgid "The fallback function is executed on a call to the contract if none of the other functions match the given function signature, or if no data was supplied at all and there is no receive Ether function. The fallback function always receives data, but in order to also receive Ether it must be marked payable."
msgstr ""
@ -2315,7 +2315,7 @@ msgid "The percentage of stake in a single pool relative to the total amount sta
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:39
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:43
msgid "The receive function is executed on a call to the contract with empty calldata. This is the function that is executed on plain Ether transfers (e.g. via .send() or .transfer()). If no such function exists, but a payable fallback function exists, the fallback function will be called on a plain Ether transfer. If neither a receive Ether nor a payable fallback function is present, the contract cannot receive Ether through regular transactions and throws an exception."
msgstr ""
@ -2467,12 +2467,12 @@ msgid "This block has not been processed yet."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:38
#: lib/block_scout_web/templates/address_contract/index.html.eex:41
msgid "This contract has been partially verified via Sourcify."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:42
#: lib/block_scout_web/templates/address_contract/index.html.eex:45
msgid "This contract has been verified via Sourcify."
msgstr ""
@ -2911,15 +2911,15 @@ msgid "Value sent in the native token (and USD) if applicable."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:79
#: lib/block_scout_web/templates/address_contract/index.html.eex:82
msgid "Verified at"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:27
#: lib/block_scout_web/templates/address_contract/index.html.eex:29 lib/block_scout_web/templates/address_contract/index.html.eex:161
#: lib/block_scout_web/templates/address_contract/index.html.eex:167 lib/block_scout_web/templates/address_contract/index.html.eex:198
#: lib/block_scout_web/templates/address_contract/index.html.eex:204 lib/block_scout_web/templates/smart_contract/_functions.html.eex:13
#: lib/block_scout_web/templates/address_contract/index.html.eex:29 lib/block_scout_web/templates/address_contract/index.html.eex:164
#: lib/block_scout_web/templates/address_contract/index.html.eex:170 lib/block_scout_web/templates/address_contract/index.html.eex:201
#: lib/block_scout_web/templates/address_contract/index.html.eex:207 lib/block_scout_web/templates/smart_contract/_functions.html.eex:14
msgid "Verify & Publish"
msgstr ""
@ -3004,7 +3004,7 @@ msgid "Vyper contract"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:127
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:131
msgid "WEI"
msgstr ""
@ -3018,6 +3018,11 @@ msgstr ""
msgid "Wallet addresses"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/common_components/_changed_bytecode_warning.html.eex:3
msgid "Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/stakes/_stakes_modal_claim_reward_content.html.eex:2
msgid "We found the following pools you can claim reward from:"
@ -3054,7 +3059,7 @@ msgid "Working Stake Amount"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:94
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:98
msgid "Write"
msgstr ""
@ -3184,7 +3189,7 @@ msgid "custom RPC"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:37
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:41
msgid "fallback"
msgstr ""
@ -3220,7 +3225,7 @@ msgid "of"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:15
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:16
msgid "page"
msgstr ""
@ -3230,7 +3235,7 @@ msgid "pool owner"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:39
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:43
msgid "receive"
msgstr ""

@ -85,6 +85,12 @@ defmodule BlockScoutWeb.AddressReadContractControllerTest do
def get_eip1967_implementation do
EthereumJSONRPC.Mox
|> expect(
:json_rpc,
fn [%{id: id, method: "eth_getCode", params: [_, _]}], _options ->
{:ok, [%{id: id, jsonrpc: "2.0", result: "0x0"}]}
end
)
|> expect(:json_rpc, fn %{
id: 0,
method: "eth_getStorageAt",

@ -82,6 +82,12 @@ defmodule BlockScoutWeb.AddressReadProxyControllerTest do
def get_eip1967_implementation do
EthereumJSONRPC.Mox
|> expect(
:json_rpc,
fn [%{id: id, method: "eth_getCode", params: [_, _]}], _options ->
{:ok, [%{id: id, jsonrpc: "2.0", result: "0x0"}]}
end
)
|> expect(:json_rpc, fn %{
id: 0,
method: "eth_getStorageAt",

@ -86,6 +86,12 @@ defmodule BlockScoutWeb.AddressWriteContractControllerTest do
def get_eip1967_implementation do
EthereumJSONRPC.Mox
|> expect(
:json_rpc,
fn [%{id: id, method: "eth_getCode", params: [_, _]}], _options ->
{:ok, [%{id: id, jsonrpc: "2.0", result: "0x0"}]}
end
)
|> expect(:json_rpc, fn %{
id: 0,
method: "eth_getStorageAt",

@ -84,6 +84,12 @@ defmodule BlockScoutWeb.AddressWriteProxyControllerTest do
def get_eip1967_implementation do
EthereumJSONRPC.Mox
|> expect(
:json_rpc,
fn [%{id: id, method: "eth_getCode", params: [_, _]}], _options ->
{:ok, [%{id: id, jsonrpc: "2.0", result: "0x0"}]}
end
)
|> expect(:json_rpc, fn %{
id: 0,
method: "eth_getStorageAt",

@ -47,6 +47,7 @@ defmodule BlockScoutWeb.SmartContractControllerTest do
insert(:smart_contract, address_hash: token_contract_address.hash)
blockchain_get_code_mock()
blockchain_get_function_mock()
path =
@ -83,6 +84,8 @@ defmodule BlockScoutWeb.SmartContractControllerTest do
]
)
blockchain_get_code_mock()
path =
smart_contract_path(BlockScoutWeb.Endpoint, :index,
hash: token_contract_address.hash,
@ -117,6 +120,7 @@ defmodule BlockScoutWeb.SmartContractControllerTest do
]
)
blockchain_get_code_mock()
blockchain_get_implementation_mock()
path =
@ -153,6 +157,7 @@ defmodule BlockScoutWeb.SmartContractControllerTest do
]
)
blockchain_get_code_mock()
blockchain_get_implementation_mock_2()
path =
@ -232,6 +237,7 @@ defmodule BlockScoutWeb.SmartContractControllerTest do
address = insert(:contract_address)
smart_contract = insert(:smart_contract, address_hash: address.hash)
blockchain_get_code_mock()
blockchain_get_function_mock()
path =
@ -269,6 +275,16 @@ defmodule BlockScoutWeb.SmartContractControllerTest do
)
end
defp blockchain_get_code_mock do
expect(
EthereumJSONRPC.Mox,
:json_rpc,
fn [%{id: id, method: "eth_getCode", params: [_, _]}], _options ->
{:ok, [%{id: id, jsonrpc: "2.0", result: "0x0"}]}
end
)
end
defp blockchain_get_implementation_mock do
expect(
EthereumJSONRPC.Mox,

@ -101,6 +101,9 @@ defmodule Explorer.Chain do
@burn_address_hash_str "0x0000000000000000000000000000000000000000"
# seconds
@check_bytecode_interval 86_400
@typedoc """
The name of an association on the `t:Ecto.Schema.t/0`
"""
@ -1700,7 +1703,7 @@ defmodule Explorer.Chain do
case address_result do
%{smart_contract: smart_contract} ->
if smart_contract do
address_result
check_bytecode_matching(address_result)
else
address_verified_twin_contract =
Chain.get_minimal_proxy_template(hash) ||
@ -1730,6 +1733,46 @@ defmodule Explorer.Chain do
end
end
defp check_bytecode_matching(address) do
now = DateTime.utc_now()
json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
if !address.smart_contract.is_changed_bytecode and
address.smart_contract.bytecode_checked_at
|> DateTime.add(@check_bytecode_interval, :second)
|> DateTime.compare(now) != :gt do
case EthereumJSONRPC.fetch_codes(
[%{block_quantity: "latest", address: address.smart_contract.address_hash}],
json_rpc_named_arguments
) do
{:ok, %EthereumJSONRPC.FetchedCodes{params_list: fetched_codes}} ->
bytecode_from_node = fetched_codes |> List.first() |> Map.get(:code)
bytecode_from_db = "0x" <> (address.contract_code.bytes |> Base.encode16(case: :lower))
if bytecode_from_node == bytecode_from_db do
{:ok, smart_contract} =
address.smart_contract
|> Changeset.change(%{bytecode_checked_at: now})
|> Repo.update()
%{address | smart_contract: smart_contract}
else
{:ok, smart_contract} =
address.smart_contract
|> Changeset.change(%{bytecode_checked_at: now, is_changed_bytecode: true})
|> Repo.update()
%{address | smart_contract: smart_contract}
end
_ ->
address
end
else
address
end
end
@spec find_decompiled_contract_address(Hash.Address.t()) :: {:ok, Address.t()} | {:error, :not_found}
def find_decompiled_contract_address(%Hash{byte_count: unquote(Hash.Address.byte_count())} = hash) do
query =

@ -195,6 +195,9 @@ defmodule Explorer.Chain.SmartContract do
* `verified_via_sourcify` - whether contract verified through Sourcify utility or not.
* `partially_verified` - whether contract verified using partial matched source code or not.
* `is_vyper_contract` - boolean flag, determines if contract is Vyper or not
* `file_path` - show the filename or path to the file of the contract source file
* `is_changed_bytecode` - boolean flag, determines if contract's bytecode was modified
* `bytecode_checked_at` - timestamp of the last check of contract's bytecode matching (DB and BlockChain)
"""
@type t :: %Explorer.Chain.SmartContract{
@ -209,7 +212,9 @@ defmodule Explorer.Chain.SmartContract do
verified_via_sourcify: boolean | nil,
partially_verified: boolean | nil,
file_path: String.t(),
is_vyper_contract: boolean | nil
is_vyper_contract: boolean | nil,
is_changed_bytecode: boolean,
bytecode_checked_at: DateTime.t()
}
schema "smart_contracts" do
@ -226,6 +231,8 @@ defmodule Explorer.Chain.SmartContract do
field(:partially_verified, :boolean)
field(:file_path, :string)
field(:is_vyper_contract, :boolean)
field(:is_changed_bytecode, :boolean, default: false)
field(:bytecode_checked_at, :utc_datetime_usec, default: DateTime.add(DateTime.utc_now(), -86400, :second))
has_many(
:decompiled_smart_contracts,
@ -263,7 +270,9 @@ defmodule Explorer.Chain.SmartContract do
:verified_via_sourcify,
:partially_verified,
:file_path,
:is_vyper_contract
:is_vyper_contract,
:is_changed_bytecode,
:bytecode_checked_at
])
|> validate_required([:name, :compiler_version, :optimization, :contract_source_code, :abi, :address_hash])
|> unique_constraint(:address_hash)
@ -291,7 +300,9 @@ defmodule Explorer.Chain.SmartContract do
:verified_via_sourcify,
:partially_verified,
:file_path,
:is_vyper_contract
:is_vyper_contract,
:is_changed_bytecode,
:bytecode_checked_at
])
|> (&if(json_verification,
do: &1,

@ -0,0 +1,13 @@
defmodule Explorer.Repo.Migrations.AddCheckForBytecodeActuality do
use Ecto.Migration
def change do
alter table(:smart_contracts) do
add(:is_changed_bytecode, :boolean, default: false)
# subtracting 1 day to perform first check
add(:bytecode_checked_at, :"timestamp without time zone",
default: fragment("(NOW() AT TIME ZONE 'utc') - INTERVAL '1 DAY'")
)
end
end
end

@ -1,6 +1,8 @@
defmodule Explorer.Chain.LogTest do
use Explorer.DataCase
import Mox
alias Ecto.Changeset
alias Explorer.Chain.{Log, SmartContract}
alias Explorer.Repo
@ -99,6 +101,8 @@ defmodule Explorer.Chain.LogTest do
data: data
)
blockchain_get_code_mock()
assert Log.decode(log, transaction) ==
{:ok, "eb9b3c4c", "WantsPets(string indexed _from_human, uint256 _number, bool indexed _belly)",
[
@ -167,4 +171,14 @@ defmodule Explorer.Chain.LogTest do
]}
end
end
defp blockchain_get_code_mock do
expect(
EthereumJSONRPC.Mox,
:json_rpc,
fn [%{id: id, method: "eth_getCode", params: [_, _]}], _options ->
{:ok, [%{id: id, jsonrpc: "2.0", result: "0x0"}]}
end
)
end
end

Loading…
Cancel
Save