@ -1,3 +1,85 @@
defmodule Explorer.Chain.SmartContract.Schema do
@moduledoc """
Models smart - contract .
"""
alias Explorer.Chain.SmartContract.ExternalLibrary
alias Explorer.Chain . {
Address ,
DecompiledSmartContract ,
Hash ,
SmartContractAdditionalSource
}
case Application . compile_env ( :explorer , :chain_type ) do
:zksync ->
@chain_type_fields quote (
do : [
field ( :optimization_runs , :string ) ,
field ( :zk_compiler_version , :string , null : true )
]
)
_ ->
@chain_type_fields quote ( do : [ field ( :optimization_runs , :integer ) ] )
end
defmacro generate do
quote do
typed_schema " smart_contracts " do
field ( :name , :string , null : false )
field ( :compiler_version , :string , null : false )
field ( :optimization , :boolean , null : false )
field ( :contract_source_code , :string , null : false )
field ( :constructor_arguments , :string )
field ( :evm_version , :string )
embeds_many ( :external_libraries , ExternalLibrary , on_replace : :delete )
field ( :abi , { :array , :map } )
field ( :verified_via_sourcify , :boolean )
field ( :verified_via_eth_bytecode_db , :boolean )
field ( :verified_via_verifier_alliance , :boolean )
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 ) )
field ( :contract_code_md5 , :string , null : false )
field ( :compiler_settings , :map )
field ( :autodetect_constructor_args , :boolean , virtual : true )
field ( :is_yul , :boolean , virtual : true )
field ( :metadata_from_verified_bytecode_twin , :boolean , virtual : true )
field ( :license_type , Ecto.Enum , values : @license_enum , default : :none )
field ( :certified , :boolean )
field ( :is_blueprint , :boolean )
has_many (
:decompiled_smart_contracts ,
DecompiledSmartContract ,
foreign_key : :address_hash
)
belongs_to (
:address ,
Address ,
foreign_key : :address_hash ,
references : :hash ,
type : Hash.Address ,
null : false
)
has_many ( :smart_contract_additional_sources , SmartContractAdditionalSource ,
references : :address_hash ,
foreign_key : :address_hash
)
timestamps ( )
unquote_splicing ( @chain_type_fields )
end
end
end
end
defmodule Explorer.Chain.SmartContract do
@moduledoc """
The representation of a verified Smart Contract .
@ -9,6 +91,7 @@ defmodule Explorer.Chain.SmartContract do
"""
require Logger
require Explorer.Chain.SmartContract.Schema
use Explorer.Schema
@ -19,7 +102,6 @@ defmodule Explorer.Chain.SmartContract do
Address ,
ContractMethod ,
Data ,
DecompiledSmartContract ,
Hash ,
InternalTransaction ,
SmartContract ,
@ -29,7 +111,7 @@ defmodule Explorer.Chain.SmartContract do
alias Explorer.Chain.Address.Name , as : AddressName
alias Explorer.Chain.SmartContract . { ExternalLibrary , Proxy }
alias Explorer.Chain.SmartContract.Proxy
alias Explorer.Chain.SmartContract.Proxy.Models.Implementation
alias Explorer.SmartContract.Helper
alias Explorer.SmartContract.Solidity.Verifier
@ -39,6 +121,21 @@ defmodule Explorer.Chain.SmartContract do
@burn_address_hash_string " 0x0000000000000000000000000000000000000000 "
@dead_address_hash_string " 0x000000000000000000000000000000000000dEaD "
@required_attrs ~w( compiler_version optimization address_hash contract_code_md5 )a
@optional_common_attrs ~w( name contract_source_code evm_version optimization_runs constructor_arguments verified_via_sourcify verified_via_eth_bytecode_db verified_via_verifier_alliance partially_verified file_path is_vyper_contract is_changed_bytecode bytecode_checked_at autodetect_constructor_args license_type certified is_blueprint )a
@optional_changeset_attrs ~w( abi compiler_settings )a
@optional_invalid_contract_changeset_attrs ~w( autodetect_constructor_args )a
@chain_type_optional_attrs ( case Application . compile_env ( :explorer , :chain_type ) do
:zksync ->
~w( zk_compiler_version )a
_ ->
~w( )a
end )
@doc """
Returns burn address hash
"""
@ -260,6 +357,12 @@ defmodule Explorer.Chain.SmartContract do
* ` name ` - the human - readable name of the smart contract .
* ` compiler_version ` - the version of the Solidity compiler used to compile ` contract_source_code ` with ` optimization `
into ` address ` ` t :Explorer.Chain.Address . t / 0 ` ` contract_code ` .
#{case Application.compile_env(:explorer, :chain_type) do
:zksync -> """
* ` zk_compiler_version ` - the version of ZkSolc or ZkVyper compilers .
"""
_ -> " "
end }
* ` optimization ` - whether optimizations were turned on when compiling ` contract_source_code ` into ` address `
` t :Explorer.Chain.Address . t / 0 ` ` contract_code ` .
* ` contract_source_code ` - the Solidity source code that was compiled by ` compiler_version ` with ` optimization ` to
@ -281,94 +384,24 @@ defmodule Explorer.Chain.SmartContract do
* ` certified ` - boolean flag , which can be set for set of smart - contracts via runtime env variable to prioritize those smart - contracts in the search .
* ` is_blueprint ` - boolean flag , determines if contract is ERC - 5202 compatible blueprint contract or not .
"""
typed_schema " smart_contracts " do
field ( :name , :string , null : false )
field ( :compiler_version , :string , null : false )
field ( :optimization , :boolean , null : false )
field ( :contract_source_code , :string , null : false )
field ( :constructor_arguments , :string )
field ( :evm_version , :string )
field ( :optimization_runs , :integer )
embeds_many ( :external_libraries , ExternalLibrary , on_replace : :delete )
field ( :abi , { :array , :map } )
field ( :verified_via_sourcify , :boolean )
field ( :verified_via_eth_bytecode_db , :boolean )
field ( :verified_via_verifier_alliance , :boolean )
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 ) )
field ( :contract_code_md5 , :string , null : false )
field ( :compiler_settings , :map )
field ( :autodetect_constructor_args , :boolean , virtual : true )
field ( :is_yul , :boolean , virtual : true )
field ( :metadata_from_verified_bytecode_twin , :boolean , virtual : true )
field ( :license_type , Ecto.Enum , values : @license_enum , default : :none )
field ( :certified , :boolean )
field ( :is_blueprint , :boolean )
has_many (
:decompiled_smart_contracts ,
DecompiledSmartContract ,
foreign_key : :address_hash
)
belongs_to (
:address ,
Address ,
foreign_key : :address_hash ,
references : :hash ,
type : Hash.Address ,
null : false
)
has_many ( :smart_contract_additional_sources , SmartContractAdditionalSource ,
references : :address_hash ,
foreign_key : :address_hash
)
timestamps ( )
end
Explorer.Chain.SmartContract.Schema . generate ( )
def preload_decompiled_smart_contract ( contract ) do
Repo . preload ( contract , :decompiled_smart_contracts )
end
def changeset ( % __MODULE__ { } = smart_contract , attrs ) do
attrs_to_cast =
@required_attrs ++
@optional_common_attrs ++
@optional_changeset_attrs ++
@chain_type_optional_attrs
required_for_validation = [ :name , :contract_source_code ] ++ @required_attrs
smart_contract
|> cast ( attrs , [
:name ,
:compiler_version ,
:optimization ,
:contract_source_code ,
:address_hash ,
:abi ,
:constructor_arguments ,
:evm_version ,
:optimization_runs ,
:verified_via_sourcify ,
:verified_via_eth_bytecode_db ,
:verified_via_verifier_alliance ,
:partially_verified ,
:file_path ,
:is_vyper_contract ,
:is_changed_bytecode ,
:bytecode_checked_at ,
:contract_code_md5 ,
:compiler_settings ,
:license_type ,
:certified ,
:is_blueprint
] )
|> validate_required ( [
:name ,
:compiler_version ,
:optimization ,
:contract_source_code ,
:address_hash ,
:contract_code_md5
] )
|> cast ( attrs , attrs_to_cast )
|> validate_required ( required_for_validation )
|> unique_constraint ( :address_hash )
|> prepare_changes ( & upsert_contract_methods / 1 )
end
@ -380,34 +413,18 @@ defmodule Explorer.Chain.SmartContract do
error_message ,
verification_with_files? \\ false
) do
attrs_to_cast =
@required_attrs ++
@optional_common_attrs ++
@optional_invalid_contract_changeset_attrs ++
@chain_type_optional_attrs
validated =
smart_contract
|> cast ( attrs , [
:name ,
:compiler_version ,
:optimization ,
:contract_source_code ,
:address_hash ,
:evm_version ,
:optimization_runs ,
:constructor_arguments ,
:verified_via_sourcify ,
:verified_via_eth_bytecode_db ,
:verified_via_verifier_alliance ,
:partially_verified ,
:file_path ,
:is_vyper_contract ,
:is_changed_bytecode ,
:bytecode_checked_at ,
:contract_code_md5 ,
:autodetect_constructor_args ,
:license_type ,
:certified ,
:is_blueprint
] )
|> cast ( attrs , attrs_to_cast )
|> ( & if ( verification_with_files? ,
do : &1 ,
else : validate_required ( &1 , [ :compiler_version , :optimization , :address_hash , :contract_code_md5 ] )
else : validate_required ( &1 , @required_attrs )
) ) . ( )
field_to_put_message = if verification_with_files? , do : :files , else : select_error_field ( error )
@ -467,15 +484,24 @@ defmodule Explorer.Chain.SmartContract do
end
def merge_twin_contract_with_changeset ( nil , % Changeset { } = changeset ) do
optimization_runs =
if Application . get_env ( :explorer , :chain_type ) == :zksync ,
do : " 0 " ,
else : " 200 "
changeset
|> Changeset . put_change ( :name , " " )
|> Changeset . put_change ( :optimization_runs , " 200 " )
|> Changeset . put_change ( :optimization_runs , optimization_runs )
|> Changeset . put_change ( :optimization , true )
|> Changeset . put_change ( :evm_version , " default " )
|> Changeset . put_change ( :compiler_version , " latest " )
|> Changeset . put_change ( :contract_source_code , " " )
|> Changeset . put_change ( :autodetect_constructor_args , true )
|> Changeset . put_change ( :is_yul , false )
|> ( & if ( Application . get_env ( :explorer , :chain_type ) == :zksync ,
do : Changeset . put_change ( &1 , :zk_compiler_version , " latest " ) ,
else : &1
) ) . ( )
end
def merge_twin_vyper_contract_with_changeset (
@ -500,6 +526,10 @@ defmodule Explorer.Chain.SmartContract do
|> Changeset . put_change ( :name , " Vyper_contract " )
|> Changeset . put_change ( :compiler_version , " latest " )
|> Changeset . put_change ( :contract_source_code , " " )
|> ( & if ( Application . get_env ( :explorer , :chain_type ) == :zksync ,
do : Changeset . put_change ( &1 , :zk_compiler_version , " latest " ) ,
else : &1
) ) . ( )
end
def license_types_enum , do : @license_enum