diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 25d1c1eeb..77aff41bb 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -395,12 +395,33 @@ void StructDefinition::insertEip712EncodedSubtypes(std::set& subtyp { 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); + Declaration const* declaration = nullptr; + switch (m_members[i]->type()->category()) + { + case Type::Category::Struct: + declaration = m_members[i]->type()->typeDefinition(); + break; + case Type::Category::Array: + { + auto const* arrayType = dynamic_cast(m_members[i]->type()); + solAssert(!!arrayType); + if (auto finalyBaseType = dynamic_cast(arrayType->finalBaseType(false))) + { + declaration = finalyBaseType->typeDefinition(); + } + } + break; + default: + continue; + } + + if(!declaration) { + continue; + } + + if (auto const* structDef = dynamic_cast(declaration)) + { subtypes.insert(structDef->eip712EncodeTypeWithoutSubtypes()); structDef->insertEip712EncodedSubtypes(subtypes); } @@ -413,16 +434,13 @@ std::string StructDefinition::eip712EncodeTypeWithoutSubtypes() const for (size_t i = 0; i < m_members.size(); i++) { str += i == 0 ? "" : ","; - str += m_members[i]->type()->canonicalName() + " " + m_members[i]->name(); + str += m_members[i]->type()->eip712TypeName() + " " + m_members[i]->name(); } return str + ")"; } std::string StructDefinition::eip712EncodeType() const { - // EIP-712 supports recurvie structs, but not containing nested mappings - solAssert(!annotation().containsNestedMapping.has_value() || !annotation().containsNestedMapping.value(), "Struct containing mapping cannot be used in EIP-712."); - // std::set enables duplicates elimination and ordered enumeration std::set subtypes; insertEip712EncodedSubtypes(subtypes); diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 70239bf56..7a916ff30 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1887,6 +1887,23 @@ string ArrayType::canonicalName() const return ret; } +string ArrayType::eip712TypeName() const +{ + string ret; + if (isString()) + ret = "string"; + else if (isByteArrayOrString()) + ret = "bytes"; + else + { + ret = baseType()->eip712TypeName() + "["; + if (!isDynamicallySized()) + ret += length().str(); + ret += "]"; + } + return ret; +} + string ArrayType::signatureInExternalFunction(bool _structsByName) const { if (isByteArrayOrString()) @@ -2511,6 +2528,11 @@ string StructType::canonicalName() const return *m_struct.annotation().canonicalName; } +string StructType::eip712TypeName() const +{ + return this->typeDefinition()->name(); +} + FunctionTypePointer StructType::constructorType() const { TypePointers paramTypes; diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 1fc0a7e17..783b2b259 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -357,6 +357,7 @@ public: /// @returns the canonical name of this type for use in library function signatures. virtual std::string canonicalName() const { return toString(true); } virtual std::string humanReadableName() const { return toString(); } + virtual std::string eip712TypeName() const { return encodingType()->toString(true); } /// @returns the signature of this type in external functions, i.e. `uint256` for integers /// or `(uint256,bytes8)[2]` for an array of structs. If @a _structsByName, /// structs are given by canonical name like `ContractName.StructName[2]`. @@ -551,6 +552,7 @@ public: bool nameable() const override { return true; } std::string toString(bool _withoutDataLocation) const override; + std::string eip712TypeName() const override{ solAssert(false, "EIP-712 is not supported for struct members of fixed point type"); } Type const* encodingType() const override { return this; } TypeResult interfaceType(bool) const override { return this; } @@ -867,6 +869,7 @@ public: std::string toString(bool _withoutDataLocation) const override; std::string humanReadableName() const override; std::string canonicalName() const override; + std::string eip712TypeName() const override; std::string signatureInExternalFunction(bool _structsByName) const override; MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override; Type const* encodingType() const override; @@ -924,6 +927,7 @@ public: BoolResult isImplicitlyConvertibleTo(Type const& _other) const override; BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; std::string richIdentifier() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of array slice type"); } bool operator==(Type const& _other) const override; unsigned calldataEncodedSize(bool) const override { solAssert(false, ""); } unsigned calldataEncodedTailSize() const override { return 32; } @@ -1052,6 +1056,7 @@ public: std::unique_ptr copyForLocation(DataLocation _location, bool _isPointer) const override; std::string canonicalName() const override; + std::string eip712TypeName() const override; std::string signatureInExternalFunction(bool _structsByName) const override; /// @returns a function that performs the type conversion between a list of struct members @@ -1100,6 +1105,7 @@ public: bool leftAligned() const override { return false; } std::string toString(bool _withoutDataLocation) const override; std::string canonicalName() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of Enum type"); } bool isValueType() const override { return true; } bool nameable() const override { return true; } @@ -1187,6 +1193,7 @@ public: std::string toString(bool _withoutDataLocation) const override; std::string canonicalName() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of user defined value type"); } std::string signatureInExternalFunction(bool) const override { solAssert(false, ""); } protected: @@ -1218,6 +1225,8 @@ public: bool hasSimpleZeroValueInMemory() const override { return false; } Type const* mobileType() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of tuple type"); } + std::vector const& components() const { return m_components; } protected: @@ -1415,6 +1424,7 @@ public: TypeResult binaryOperatorResult(Token, Type const*) const override; std::string canonicalName() const override; std::string humanReadableName() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of function type"); } std::string toString(bool _withoutDataLocation) const override; unsigned calldataEncodedSize(bool _padded) const override; bool canBeStored() const override { return m_kind == Kind::Internal || m_kind == Kind::External; } @@ -1551,6 +1561,7 @@ public: bool operator==(Type const& _other) const override; std::string toString(bool _withoutDataLocation) const override; std::string canonicalName() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of mapping type"); } bool containsNestedMapping() const override { return true; } TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; } Type const* encodingType() const override; @@ -1595,6 +1606,7 @@ public: bool operator==(Type const& _other) const override; bool canBeStored() const override { return false; } u256 storageSize() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of type type"); } bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); } std::string toString(bool _withoutDataLocation) const override { return "type(" + m_actualType->toString(_withoutDataLocation) + ")"; } MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override; @@ -1622,6 +1634,7 @@ public: u256 storageSize() const override; bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); } std::string richIdentifier() const override; + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of modfier type"); } bool operator==(Type const& _other) const override; std::string toString(bool _withoutDataLocation) const override; protected: @@ -1646,6 +1659,7 @@ public: std::string richIdentifier() const override; bool operator==(Type const& _other) const override; bool canBeStored() const override { return false; } + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of module type"); } bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); } MemberList::MemberMap nativeMembers(ASTNode const*) const override; @@ -1685,6 +1699,7 @@ public: std::string richIdentifier() const override; bool operator==(Type const& _other) const override; bool canBeStored() const override { return false; } + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of magic type"); } bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); } MemberList::MemberMap nativeMembers(ASTNode const*) const override; @@ -1718,6 +1733,7 @@ public: unsigned calldataEncodedSize(bool) const override { return 32; } bool canBeStored() const override { return false; } bool isValueType() const override { return true; } + std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of inaccessible dynamic type"); } bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); } std::string toString(bool) const override { return "inaccessible dynamic type"; } Type const* decodingType() const override;