Skip to content

feat[lang]: make interfaces subtypes of address - #5228

Open
Sporarum wants to merge 2 commits into
vyperlang:masterfrom
Sporarum:uniformly-allow-interface-to-address-widening
Open

Sporarum wants to merge 2 commits into
vyperlang:masterfrom
Sporarum:uniformly-allow-interface-to-address-widening

Conversation

@Sporarum

Copy link
Copy Markdown
Collaborator

What I did

Allow widening interfaces to addresses:
An interface value can be used anywhere an address is expected, for example:

  • a: addr = token (where token: IERC20)
  • Using a public addr to implement a method returning an address

Previously the latter was allowed by forcing the getter to return an address, this caused #4721.
The new logic only widens when needed, both cases are allowed:
asset: public(IERC20) can implement both def asset() -> IERC20 and def asset() -> address

Fix #3954
Fix #4721
Implement #3701 (comment) (note: not the issue as a whole, only this comment)

How I did it

Make interfaces subtypes of address: for any SomeInterface an InterfaceT: SomeInterface <: AddressT
Remove the special case that public interface members return an address

How to verify it

pytest

See added tests

Commit message

before this commit interfaces were allowed in places where an address
was expected in exactly one situation: when using a public interface
member to implement an address-returning method. this commit extends
this capability to all locations: anywhere an address is expected, an
interface instance can be provided.

Description for the changelog

Allow assigning interfaces where addresses are expected
Fix code like asset: public(IERC20) not being allowed to implement def asset() -> IERC20

Cute Animal Picture

Put a link to a cute animal picture inside the parenthesis-->

)

def compare_type(self, other):
from vyper.semantics.types.module import InterfaceT

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be solved once we refactor compare_type away

@github-actions

Copy link
Copy Markdown

Gas Changes

No changes detected.

Summary

  • Total tests measured: 560
  • Changed: 0
  • Regressions (gas up): 0
  • Improvements (gas down): 0
  • New tests: 0
  • Deleted tests: 0
  • Newly failing: 0
  • Newly passing: 0

@charles-cooper charles-cooper changed the title feat[lang]: allow widening interfaces to addresses feat[lang]!: allow widening interfaces to addresses Aug 28, 2026
@charles-cooper charles-cooper changed the title feat[lang]!: allow widening interfaces to addresses feat[lang]!: make interfaces subtypes of address Aug 28, 2026
@charles-cooper charles-cooper changed the title feat[lang]!: make interfaces subtypes of address feat[lang]!: make interfaces subtypes of address Aug 28, 2026

@charles-cooper charles-cooper left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm pending clanker review

@github-actions

Copy link
Copy Markdown

📊 Bytecode Size Changes (venom)

No changes detected.

Full bytecode sizes

Contract legacy-O2 legacy-Os -O2 -O3 -Os
curvefi/legacy/CurveStableSwapMetaNG.vy 24952 23578 20309 19555 19002
curvefi/amm/stableswap/meta_implementation/meta_implementation_v_700.vy 23610 22805 20230 19166 18919
curvefi/amm/stableswap/implementation/implementation_v_700.vy 24962 23769 19601 18789 18371
curvefi/legacy/CurveStableSwapNG.vy 24473 23298 19158 18392 17984
curvefi/amm/tricryptoswap/implementation/implementation_v_200.vy 20724 19959 17563 17045 16637
curvefi/amm/twocryptoswap/implementation/implementation_v_210.vy 17634 16894 15264 14665 14333
yearnfi/VaultV3.vy 19972 19063 14968 14047 13496
curvefi/legacy/CurveCryptoSwap2.vy 18947 18382 14924 14434 14259
yearnfi/VaultV2.vy 16676 15763 13365 12573 12156
curvefi/amm/stableswap/factory/factory_v_100.vy 14558 13978 12110 10918 11018
curvefi/gauge/child_gauge/implementation/implementation_v_110.vy 12338 11561 10043 9386 8997
curvefi/gauge/child_gauge/implementation/implementation_v_100.vy 12017 11249 9774 9124 8738
curvefi/amm/stableswap/views/views_v_120.vy 12784 12368 9744 9121 9332
curvefi/amm/tricryptoswap/math/math_v_200.vy 11189 11126 9012 7960 8153
curvefi/legacy/CurveCryptoMathOptimized3.vy 11188 11125 9011 7960 8153
curvefi/gauge/child_gauge/implementation/implementation_v_020.vy 10665 9947 8870 8284 7898
curvefi/registries/metaregistry/metaregistry_v_110.vy 7590 6732 6523 5742 5635
curvefi/helpers/router/router_v_110.vy 6717 6717 6505 5987 6289
curvefi/amm/tricryptoswap/views/views_v_200.vy 7821 7776 6291 6071 6225
curvefi/helpers/stable_swap_meta_zap/stable_swap_meta_zap_v_100.vy 7302 7067 6201 5714 5934
curvefi/amm/twocryptoswap/views/views_v_200.vy 6991 6946 5872 5666 5806
curvefi/registries/metaregistry/registry_handlers/stableswap/handler_v_110.vy 6633 6259 5722 4877 5427
curvefi/amm/twocryptoswap/math/math_v_210.vy 6800 6800 5506 5012 5039
curvefi/amm/twocryptoswap/factory/factory_v_200.vy 5540 5252 4839 4019 4153
curvefi/amm/tricryptoswap/factory/factory_v_200.vy 5246 5021 4712 3999 4129
curvefi/gauge/child_gauge/factory/factory_v_201.vy 4844 4547 4155 3869 3705
curvefi/registries/metaregistry/registry_handlers/tricryptoswap/handler_v_110.vy 4241 3939 3761 3410 3472
curvefi/registries/metaregistry/registry_handlers/twocryptoswap/handler_v_110.vy 4186 3884 3701 3281 3359
curvefi/gauge/child_gauge/factory/factory_v_100.vy 4183 3914 3636 3312 3139
yearnfi/VaultFactory.vy 3765 3617 3157 2257 2562
curvefi/registries/address_provider/address_provider_v_201.vy 2973 2782 2631 2427 2339
curvefi/helpers/rate_provider/rate_provider_v_101.vy 3260 3260 2598 2326 2359
curvefi/amm/stableswap/math/math_v_100.vy 3067 3046 2442 2237 2293
curvefi/helpers/rate_provider/rate_provider_v_100.vy 2847 2841 2326 2007 2027
curvefi/helpers/deposit_and_stake_zap/deposit_and_stake_zap_v_100.vy 2322 2316 1883 1712 1771
curvefi/governance/relayer/taiko/relayer_v_001.vy 2068 2064 1766 1545 1593
curvefi/governance/relayer/polygon_cdk/relayer_v_101.vy 1556 1523 1554 1348 1371
curvefi/governance/relayer/arb_orbit/relayer_v_101.vy 1266 1262 1253 1077 1126
curvefi/governance/relayer/op_stack/relayer_v_101.vy 1186 1182 1194 1025 1067
curvefi/governance/relayer/not_rollup/relayer_v_100.vy 1168 1153 1185 1022 1048
curvefi/governance/vault/vault_v_100.vy 964 941 873 834 850
curvefi/governance/relayer/relayer_v_100.vy 496 496 593 490 503
curvefi/governance/agent/agent_v_100.vy 541 541 425 397 401
curvefi/governance/agent/agent_v_101.vy 541 541 425 397 401

@charles-cooper charles-cooper changed the title feat[lang]!: make interfaces subtypes of address feat[lang]: make interfaces subtypes of address Aug 28, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6fc664a5a7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

from vyper.semantics.types.module import InterfaceT

# interfaces can be widened to addresses
return isinstance(other, InterfaceT) or super().compare_type(other)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add address to common-type inference for interfaces

This subtype hook makes an individual interface acceptable where address is expected, but expressions that first compute a common type still fail for two different interface types because get_common_types() only selects one of the operands' possible types and never adds their AddressT supertype. For example, in a function returning address, return a if cond else b still raises TypeMismatch when a: IFoo and b: IBar, and the same applies to list literals such as [a, b] assigned to DynArray[address, ...], even though each operand is now meant to widen to an address. Please either add AddressT as the common candidate for interface/address operands or contextually type these expression forms against the expected address.

Useful? React with 👍 / 👎.

Comment on lines 80 to 82
@property
def abi_type(self) -> ABIType:
return ABI_Address()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Emit address for standalone public getter interfaces

With the getter override removed here, foo: public(IERC20) now has a getter return type of IERC20, so external_interface/interface output prints def foo() -> IERC20 without also emitting the import or interface definition needed to resolve IERC20. That regresses the common use case where generated interface output is consumed as a standalone .vyi; before this change the same getter printed -> address and remained self-contained. Please keep generated interface text self-contained, e.g. by rendering public interface getter returns as their ABI address type or by emitting the required interface definition/import.

Useful? React with 👍 / 👎.

from vyper.semantics.types.module import InterfaceT

# interfaces can be widened to addresses
return isinstance(other, InterfaceT) or super().compare_type(other)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept interfaces in address-array membership checks

This only teaches direct expected-type checks that an interface is assignable to address; membership validation still uses _is_type_in_list()/is_equivalent_to(), so a in xs is rejected when a: IFoo and xs: DynArray[address, 3] with Cannot perform membership comparison between dislike types. Since the array element type is an address position and the generated comparison would be a word equality, this leaves another address-expected context that the new widening rule does not cover.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants