5/5
## Deploying Vyper Contracts to a Tenderly Virtual Network This lesson guides you through deploying a Vyper smart contract to a Tenderly Virtual Network. We'll use a specific example, `buy_me_a_coffee.vy`, to demonstrate the process. Tenderly Virtual Networks provide a powerful testing environment by allowing you to fork an existing blockchain (like Sepolia) at a specific block. This creates a private, simulated environment that includes the entire state of the forked chain, enabling realistic testing scenarios, including interactions with existing contracts deployed on the main network. Our goal is to deploy our Vyper contract and interact with an external Chainlink Price Feed contract within this simulated Tenderly environment. ### Prerequisites Before proceeding, ensure you have the following set up: * A registered Tenderly account with an application configured. * A Tenderly Virtual TestNet created, based on the Sepolia network (referred to as "Our fake chain" in the related video). * MetaMask browser extension installed. * MetaMask configured with a custom network pointing to the RPC URL of your Tenderly Virtual TestNet ("Our fake chain"). ### Deployment Steps using Remix IDE Follow these steps to compile and deploy your Vyper contract using the Remix IDE: 1. **Open Contract:** Ensure the `buy_me_a_coffee.vy` contract file is open in your Remix IDE workspace. 2. **Compile:** Navigate to the "Vyper Compiler" tab (look for the Vyper logo). Select the correct compiler version if necessary, and click "Compile buy_me_a_coffee.vy". Wait for the compilation to succeed. 3. **Configure Deployment Environment:** Go to the "Deploy & Run Transactions" tab (Ethereum logo). In the "ENVIRONMENT" dropdown menu, change the selection from any "Remix VM" option to "Injected Provider - MetaMask". Remix will prompt you to connect your MetaMask wallet if it's not already connected. 4. **Select Network in MetaMask:** Open your MetaMask extension. Ensure that the network selected is your custom Tenderly Virtual TestNet ("Our fake chain"). Remix will now interact with this specific network via MetaMask. 5. **Select Contract:** Back in Remix's "Deploy & Run Transactions" tab, look for the "CONTRACT" dropdown. * *(Potential Remix Workaround)*: Occasionally, after compiling a Vyper contract, it might not immediately appear in the "CONTRACT" dropdown. If you encounter this, a temporary workaround is to switch to the "Solidity Compiler" tab, compile any `.sol` file (e.g., a default contract), and then immediately return to the "Deploy & Run Transactions" tab. This often refreshes the contract list, and your compiled Vyper contract (`buy_me_a_coffee - buy_me_a_coffee.vy`) should now be available for selection. 6. **Choose Contract:** Select your compiled Vyper contract (`buy_me_a_coffee - buy_me_a_coffee.vy`) from the "CONTRACT" dropdown. 7. **Deploy:** Click the orange "Deploy" button. 8. **Confirm Transaction:** MetaMask will pop up, asking you to confirm the contract deployment transaction. Review the details, including the estimated gas fee (which will be deducted from the simulated ETH provided by Tenderly for your virtual network address), and click "Confirm". 9. **Verify Deployment:** The transaction will be sent to your Tenderly Virtual Network. Once confirmed (which is usually instantaneous on Tenderly), your deployed contract instance will appear under the "Deployed Contracts" section in Remix, showing its address on the virtual network. ### Interacting with the Deployed Contract on Tenderly Now that the contract is deployed, let's explore how it interacts within the Tenderly environment and call one of its functions. **Understanding Tenderly Virtual Network State** Navigate to your Tenderly dashboard and view your Virtual TestNets. You'll see "Our fake chain" listed, confirming it's based on the Sepolia network. Notice the "State Sync" setting – it will likely be disabled (indicated by an 'X'). This is a crucial point: **With State Sync disabled, your Tenderly Virtual Network is a static snapshot of the Sepolia blockchain captured at the exact moment the virtual network was created.** It does *not* automatically update with new blocks or state changes occurring on the live Sepolia network after the fork was made. The primary implication is that any interaction with contracts that existed on Sepolia *at the time of the fork* will reflect the state of that contract *at that specific historical moment*. For example, when our deployed contract calls the Chainlink Price Feed, it will retrieve the price data that was present on Sepolia when we created "Our fake chain", not the current, live market price. *Tip:* It's generally recommended to keep State Sync turned off for most testing scenarios, as enabling it might incur costs on the Tenderly platform. **Calling the `get_price` Function** 1. Return to the Remix IDE, specifically the "Deploy & Run Transactions" tab. 2. Under "Deployed Contracts", find your deployed `BUY_ME_A_COFFEE` instance. Expand it to view its functions. 3. Locate the `get_price` function button (usually displayed in blue for view/pure functions) and click it. 4. **Result:** The function executes instantly, and the returned value will appear below the button. You should see the integer `307547580000`. This represents the ETH/USD price (with appropriate decimals) fetched from the Chainlink AggregatorV3 contract *as it existed on Sepolia when the Tenderly fork was initiated*. ### Key Concepts for External Contract Interaction To successfully interact with another smart contract from within your Vyper contract, you fundamentally need two pieces of information: 1. **Address:** The unique on-chain address where the target external contract is deployed. For our example, interacting with the Chainlink ETH/USD Price Feed on Sepolia, the address is `0x694AA1769357215DE4FAC081bf1f309aD`. You typically find these addresses in the official documentation of the protocol or service you want to integrate with (e.g., Chainlink documentation). 2. **ABI (Application Binary Interface):** A standardized description of the contract's functions, including their names, input parameters (and their types), and return values (and their types). The ABI essentially defines *how* to communicate with the contract's functions correctly. **Vyper Interfaces** In Vyper, you define the ABI for an external contract you wish to interact with using an `interface`. The interface declares the function signatures (name, parameters, return type, and state mutability like `view`) that your contract needs to call. For the Chainlink Price Feed, the relevant interface within `buy_me_a_coffee.vy` looks like this: ```vyper interface AggregatorV3Interface: def decimals() -> uint8: view def description() -> String[1000]: view def version() -> uint256: view # This is the function we need to call: def latestAnswer() -> int256: view ``` This interface definition informs the Vyper compiler about the structure of the `latestAnswer` function (and others, though they aren't used in `get_price`) available on contracts adhering to this interface. **`get_price` Function Analysis** Let's examine the `get_price` function in `buy_me_a_coffee.vy` to see how the Address and ABI (via the interface) are combined: ```vyper @external @view def get_price() -> int256: # Instantiate the external contract: # Pass the known ADDRESS as an argument to the INTERFACE (ABI) price_feed: AggregatorV3Interface = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aD) # ABI <- Defined by AggregatorV3Interface # Address <- 0x694AA1769357215DE4FAC081bf1f309aD # Call the external function using staticcall # staticcall is used because latestAnswer() is a 'view' function (read-only) return staticcall price_feed.latestAnswer() ``` This code first creates a contract instance (`price_feed`) representing the external Chainlink contract by providing its `Address` to the `AggregatorV3Interface` `interface` definition (which supplies the `ABI`). Then, it calls the `latestAnswer` function on this instance. **Understanding `staticcall`** Vyper provides low-level call opcodes for interacting with other contracts. `staticcall` is specifically used when calling external functions that are guaranteed *not* to modify the blockchain state (i.e., functions marked as `view` or `pure` in Solidity or Vyper). It's a safer and more gas-efficient way to perform read-only calls compared to `extcall`. Since `latestAnswer()` in the Chainlink interface is a `view` function, `staticcall` is the appropriate mechanism. If we were calling an external function that *did* modify state, we would typically use `extcall` instead. ### Conclusion You have successfully deployed a Vyper contract to a Tenderly Virtual Network, observed the behavior of this simulated environment (particularly the implications of disabled State Sync), and interacted with an external contract (Chainlink Price Feed) using its Address and ABI (defined via a Vyper `interface`). Key concepts like `interface`, `staticcall`, ABI, and Address are fundamental to smart contract development and interoperability. While concepts like interfaces and low-level calls might seem complex initially, they will become clearer with practice and repeated exposure. Don't hesitate to review these concepts and experiment further within the Tenderly environment. Finally, remember to switch your Remix environment back to "Remix VM (Cancun)" or your preferred default setting if you are continuing with other development tasks unrelated to the Tenderly Virtual Network.
A practical guide to Deploying Vyper Contracts to a Tenderly Virtual Network - Master deploying Vyper contracts to Tenderly Virtual Networks via Remix IDE. Learn how these forked environments enable testing interactions with external contracts like Chainlink, understanding ABI and interfaces.
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