diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 1166d8ffd..566187191 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -389,22 +389,39 @@ std::vector, std::optional>> UsingFo return ranges::zip_view(m_functionsOrLibrary, m_operators) | ranges::to; } -std::string StructDefinition::encodeType() const +void StructDefinition::insertEncodedSubtypes(std::set& subtypes) const +{ + for (size_t i = 0; i < m_members.size(); i++) + { + if (m_members[i]->type()->category() == Type::Category::Struct) + { + Declaration const* declaration = m_members[i]->type()->typeDefinition(); + StructDefinition const* structDef = dynamic_cast(declaration); + solAssert(structDef != nullptr); + + subtypes.insert(structDef->encodeTypeWithoutSubtypes()); + structDef->insertEncodedSubtypes(subtypes); + } + } +} + +std::string StructDefinition::encodeTypeWithoutSubtypes() const { std::string str = name() + "("; - std::set nested; // std::set enables duplicates elimination and ordered enumeration for (size_t i = 0; i < m_members.size(); i++) { str += i == 0 ? "" : ","; str += m_members[i]->type()->canonicalName() + " " + m_members[i]->name(); - if (m_members[i]->type()->category() == Type::Category::Struct) { - Declaration const* declaration = m_members[i]->type()->typeDefinition(); - if (StructDefinition const* structDef = dynamic_cast(declaration)) { - nested.insert(structDef->encodeType()); - } - } } - return std::accumulate(nested.begin(), nested.end(), str + ")"); + return str + ")"; +} + +std::string StructDefinition::encodeType() const +{ + // std::set enables duplicates elimination and ordered enumeration + std::set subtypes; + insertEncodedSubtypes(subtypes); + return std::accumulate(subtypes.begin(), subtypes.end(), encodeTypeWithoutSubtypes()); } util::h256 StructDefinition::typehash() const diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 2d5cce81c..e11cda10e 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -741,7 +741,13 @@ public: std::vector> const& members() const { return m_members; } - /// @returns the EIP-712 compatible struct encoding. + /// Fills set with the EIP-712 compatible struct encodings without subtypes concatenated. + void insertEncodedSubtypes(std::set& subtypes) const; + + /// @returns the EIP-712 compatible struct encoding but without subtypes concatenated. + std::string encodeTypeWithoutSubtypes() const; + + /// @returns the EIP-712 compatible struct encoding with subtypes sorted and concatenated. std::string encodeType() const; /// @returns the EIP-712 compatible typehash of this struct. diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 2cbecadd3..277b81fec 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1944,8 +1944,10 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) else if (member == "typehash") { Type const* arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); - auto const& structType = dynamic_cast(*arg); - StructDefinition const& struct_ = structType.structDefinition(); + solAssert(arg != nullptr); + StructType const* structType = dynamic_cast(arg); + solAssert(structType != nullptr); + StructDefinition const& struct_ = structType->structDefinition(); define(_memberAccess) << formatNumber(struct_.typehash()) << "\n"; } else if (member == "min" || member == "max")