low

ContractFunctionT.from_abi fails to gracefully handle a valid JSON ABI interf...

Reward

Total

455.95 USDC

Selected
455.95 USDC
Selected Submission

ContractFunctionT.from_abi fails to gracefully handle a valid JSON ABI interface that represents __default__ and/or __init__ function

Severity

Low Risk

Relevant GitHub Links

https://github.com/vyperlang/vyper/blob/v0.3.10rc3/vyper/semantics/types/function.py#L128

Summary

ContractFunctionT.from_abi can't handle code with default and/or init methods provided with the object from a valid JSON ABI interface representing a function.

Vulnerability Details

Both `__init__` and `__default__` methods are missing `name` and `inputs` items respectively (although due to valid reasons) in their ABIs which leads to `ContractFunctionT.from_abi` method failure to generate a `ContractFunctionT` object.
Steps to reproduce:
1 - add sample `.vy` code to a standalone file
2 - produce abi by running `vyper -f abi <path-to-the-file>`:
root@06f545b1d4b9:/workspaces/vyper# vyper -f abi tests/sample_code_from_abi.vy         
[{"stateMutability": "nonpayable", "type": "constructor", "inputs": [], "outputs": []}, {"stateMutability": "nonpayable", "type": "fallback"}]    
3 - pass ABI payload to `ContractFunctionT.from_abi` method
4 - confirm asserts fail with KeyError for both cases

Add a new test test_init_and_default_fail_to_create_from_abi.py:

import pytest
from vyper.semantics.types.function import ContractFunctionT

@pytest.mark.xfail(raises=KeyError)
def test_init_and_default_fail_to_create_from_abi():
    # content of tests/sample_code_from_abi.vy
    code = """
owner: address
last_sender: address

@external
def __init__():
    self.owner = msg.sender

@external
def __default__():
    self.last_sender = msg.sender
    """
    abi_payload = [{"stateMutability": "nonpayable", "type": "constructor", "inputs": [], "outputs": []}, {"stateMutability": "nonpayable", "type": "fallback"}]       

    init_fn_from_abi=abi_payload[0]
    #Fails with KeyError: 'name'
    init_fn_t = ContractFunctionT.from_abi(abi=init_fn_from_abi)

    default_fn_from_abi=abi_payload[1]
    #Fails with KeyError: 'inputs'
    default_fn_t = ContractFunctionT.from_abi(abi=default_fn_from_abi)

Impact

Leaving unhandled exceptions can often lead to debugging challenges, unclear behavior, and broken client code.

Tools Used

pytest, manual review

Recommendations

Introduce graceful handling of missing items for these 2 built-in methods to ContractFunctionT.from_abi