5/5
## Using In-Line Interfaces in Vyper for Smart Contract Interaction Interacting with other smart contracts is a fundamental aspect of building complex decentralized applications. Vyper, a Pythonic smart contract language for the EVM, provides a clear mechanism for this: **Interfaces**. This lesson explores how to define and use **In-Line Interfaces** directly within your Vyper contract file to communicate with other deployed contracts on the blockchain. ### What Are Interfaces? In programming, an interface acts as a blueprint or a contract specification. It defines *what* functions are available and *how* they can be called (their names, required inputs, expected outputs, and behavior like whether they modify state). Crucially, an interface **does not contain the actual implementation** or logic of those functions. It only describes the structure for interaction. In Vyper, interfaces serve this exact purpose. They allow your contract to know the function signatures of another contract you want to interact with, enabling type-safe calls between them. ### Vyper Interfaces vs. Application Binary Interface (ABI) You might be familiar with the Application Binary Interface (ABI). The ABI is typically a JSON file generated during contract compilation. It serves a similar purpose to a Vyper interface: it describes the contract's functions (names, inputs, outputs, types, state mutability) so external applications or other contracts know how to encode calls and decode results. Both Vyper Interfaces and ABIs describe *how* to interact with a contract. The key difference lies in their usage: * **Vyper Interface:** Defined *within* Vyper code (often in `.vy` or `.vyi` files). Used by the Vyper compiler to understand and validate calls to other contracts during compilation. Enables direct, type-safe contract-to-contract calls within Vyper. * **ABI:** A JSON representation generated *after* compilation. Used primarily by *external* clients (like web frontends using libraries like ethers.js or web3.py) or potentially other off-chain services to interact with the deployed contract. For example, if you modify a function signature in your Vyper code (e.g., adding an input parameter to a `withdraw` function), both the internal interface definition (if interacting with it from another contract) and the generated ABI would need to reflect this change for interactions to work correctly. ### Defining an In-Line Interface Vyper allows you to define an interface directly within the same `.vy` file as your main contract code. This is known as an **In-Line Interface** and is convenient for simpler interactions or when you don't want to manage separate interface files (though importing interfaces from `.vyi` files is common for larger projects and will be covered later). An in-line interface definition typically appears near the top of the file, after pragmas and before contract state variables or functions. It uses the `interface` keyword followed by a name and then lists the function signatures without any implementation body (no `pass` statement or logic). Here's an example defining an interface for Chainlink's `AggregatorV3Interface`, commonly used for fetching price data: ```vyper # Defining the interface directly in the contract file interface AggregatorV3Interface: def decimals() -> uint8: view def description() -> String[1000]: view def version() -> uint256: view # Function to get the latest price data def latestAnswer() -> int256: view # Other functions like getRoundData, latestRoundData might also be included # depending on what your contract needs to call. ``` **Key points about the syntax:** * `interface AggregatorV3Interface:` starts the definition. * Each line inside defines a function signature using `def function_name(inputs) -> output: mutability`. * Note the absence of a colon `:` after the function signature and *no indented code block* below it. * `view` indicates the function does not modify the blockchain state. Other mutability options like `nonpayable` or `payable` are also possible, mirroring regular function definitions. This interface tells our Vyper contract that any contract address we associate with `AggregatorV3Interface` is expected to have these functions available with these specific signatures. ### Using the Interface to Interact with Another Contract Once you have defined the interface, you can use it to call functions on a deployed contract that implements that interface. This involves three main steps: 1. **Get the Target Contract Address:** You need the blockchain address of the deployed contract you want to interact with. For example, you can find Chainlink Price Feed addresses in the official Chainlink documentation. 2. **Instantiate the Interface:** In your Vyper function, you create an instance of the interface, associating it with the target contract's address. This is done by "casting" the address to the interface type: `InterfaceName(contract_address)`. 3. **Call the Function:** You can now call any function defined in the interface on the instance variable you created. Let's see this in action with a function that retrieves the latest ETH/USD price from a Chainlink feed on the Sepolia testnet: ```vyper # Assuming AggregatorV3Interface is defined above as shown previously # Example Sepolia ETH/USD Price Feed Address # Always verify the correct address for your network from Chainlink docs CHAINLINK_ETH_USD_PRICE_FEED: constant(address) = 0x694AA1769357215DE4FAC081bf1f309aDC325306 @external def get_latest_eth_price() -> int256: """ Gets the latest ETH/USD price from the Chainlink Price Feed contract. """ # 1. Define the interface variable type (optional, can be done in instantiation) price_feed_interface: AggregatorV3Interface # 2. Instantiate the interface with the deployed contract's address price_feed_interface = AggregatorV3Interface(CHAINLINK_ETH_USD_PRICE_FEED) # 3. Call the function defined in the interface latest_price: int256 = price_feed_interface.latestAnswer() return latest_price ``` **Explanation:** * We define a constant `CHAINLINK_ETH_USD_PRICE_FEED` holding the address of the deployed Chainlink contract (obtained from their documentation). * Inside `get_latest_eth_price`, we declare a variable `price_feed_interface` of type `AggregatorV3Interface`. * The line `price_feed_interface = AggregatorV3Interface(CHAINLINK_ETH_USD_PRICE_FEED)` is crucial. It tells Vyper: "Treat the contract located at `CHAINLINK_ETH_USD_PRICE_FEED` as if it adheres to the `AggregatorV3Interface` structure." * We can then directly call `price_feed_interface.latestAnswer()`. Vyper knows, based on the interface definition, that this function exists on the target contract, takes no arguments, returns an `int256`, and is a `view` function. * The function returns the fetched price. Before deploying, you can often verify the functions available on the target contract address using a block explorer like Etherscan. Navigate to the contract address, look for the "Contract" tab, and check the "Read Contract" or "Write Contract" sections to ensure the functions and their signatures match your interface definition. ### Conclusion Vyper interfaces are essential for enabling secure and type-safe communication between smart contracts. In-line interfaces provide a convenient way to define the interaction blueprint directly within your contract file. By defining the function signatures of a target contract, instantiating the interface with the target's address, and calling functions through the interface variable, your contract can leverage the functionality of other deployed contracts, such as fetching reliable off-chain data via oracles like Chainlink.
A practical guide to Using In-Line Interfaces in Vyper for Smart Contract Interaction - Learn how to define interaction blueprints directly within your Vyper contract and use them to securely call functions on external deployed contracts like Chainlink.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Course Overview
About the course
The basics of blockchain transactions, how to send and receive money on a blockchain network.
How to write Python based smart contracts using Vyper.
How to read and understand Vyper smart contracts.
Vyper data structures, arrays, structs, hash maps.
How to build a smart contract application and deploy on ZKsync with Moccasin.
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
On-chain Data Analyst
$59,000 - $139,000 (avg. salary)
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Last updated on June 11, 2025
Duration: 2h 08min
Duration: 2h 32min
Duration: 24min
Course Overview
About the course
The basics of blockchain transactions, how to send and receive money on a blockchain network.
How to write Python based smart contracts using Vyper.
How to read and understand Vyper smart contracts.
Vyper data structures, arrays, structs, hash maps.
How to build a smart contract application and deploy on ZKsync with Moccasin.
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
On-chain Data Analyst
$59,000 - $139,000 (avg. salary)
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Last updated on June 11, 2025