-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 709c0d8
Showing
15 changed files
with
1,509 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
RPC_URL=https://asdfasdfs | ||
# NEVER DO THIS WITH A REAL KEY!!! | ||
# We will show you encryption methods later ;) | ||
PRIVATE_KEY="my_bad_key" | ||
MY_ADDRESS="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.venv | ||
.env | ||
.password | ||
keystore.json | ||
.keystore.json | ||
.ruff_cache | ||
__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
# web3py Favorites | ||
|
||
This is from the [Cyfrin Updraft Vyper Course](). | ||
|
||
- [web3py Favorites](#web3py-favorites) | ||
- [Getting Started](#getting-started) | ||
- [Prerequisites](#prerequisites) | ||
- [Optional prerequisites](#optional-prerequisites) | ||
- [Installation](#installation) | ||
- [uv](#uv) | ||
- [pip/python](#pippython) | ||
- [Quickstart](#quickstart) | ||
- [Deploying with Python](#deploying-with-python) | ||
- [1. Setup Tenderly Virtual Network](#1-setup-tenderly-virtual-network) | ||
- [2. Fund a wallet](#2-fund-a-wallet) | ||
- [3. Get your RPC URL](#3-get-your-rpc-url) | ||
- [The Unsafe Way](#the-unsafe-way) | ||
- [4. Run the unsafe version](#4-run-the-unsafe-version) | ||
- [The Safer Way](#the-safer-way) | ||
- [4. Encrypt your private key](#4-encrypt-your-private-key) | ||
- [5. Run the safe version](#5-run-the-safe-version) | ||
- [Maintainer notes](#maintainer-notes) | ||
- [Build a new requirements.txt](#build-a-new-requirementstxt) | ||
|
||
|
||
# Getting Started | ||
|
||
## Prerequisites | ||
|
||
- [uv](https://docs.astral.sh/uv/) | ||
- You'll know you've done it right if you can run `uv --version` and see a version number. | ||
- [git](https://git-scm.com/) | ||
- You'll know you've done it right if you can run `git --version` and see a version number. | ||
|
||
### Optional prerequisites | ||
|
||
If you're an advanced python user, you can use virtual environments and classic python/pip to work here. | ||
|
||
- [python](https://www.python.org/) | ||
- [pip](https://pypi.org/project/pip/) | ||
|
||
## Installation | ||
|
||
```bash | ||
git clone https://github.com/cyfrin/web3py-favorites-cu | ||
cd web3py-favorites-cu | ||
``` | ||
|
||
### uv | ||
|
||
```bash | ||
uv sync | ||
``` | ||
|
||
### pip/python | ||
|
||
```bash | ||
python -m venv ./venv | ||
source ./venv/bin/activate | ||
pip install -r requirements.txt | ||
``` | ||
|
||
## Quickstart | ||
|
||
```bash | ||
uv run hello.py # for UV | ||
# or | ||
python hello.py # for pip/python | ||
``` | ||
|
||
# Deploying with Python | ||
|
||
## 1. Setup Tenderly Virtual Network | ||
|
||
Go to [tenderly](https://dashboard.tenderly.co/) and sign up, and then select `Create Virtual TestNet`. | ||
|
||
![Tenderly Virtual Network](./img/virtual_network.png) | ||
|
||
Your config should look like this: | ||
|
||
![Tenderly Virtual Network](./img/config.png) | ||
|
||
## 2. Fund a wallet | ||
|
||
Select your network, and hit `Fund Account` and paste in an address. | ||
|
||
We recommend using `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266` since it's a well-known testing address. | ||
|
||
![Tenderly Virtual Network](./img/fund.png) | ||
|
||
## 3. Get your RPC URL | ||
|
||
Create a `.env` file, get your RPC URL from the tenderly dashboard, and add it to your `.env` file. | ||
|
||
![Tenderly Virtual Network](./img/RPC.png) | ||
|
||
Example `.env`: | ||
|
||
```bash | ||
RPC_URL=https://asdfasdfs | ||
``` | ||
|
||
## The Unsafe Way | ||
|
||
### 4. Run the unsafe version | ||
|
||
Add your private key to your `.env` file. This should be the private key associated with the account you funded. If you used the address above, use the following: | ||
|
||
_example `.env`_ | ||
```bash | ||
RPC_URL="your_rpc_url" | ||
|
||
# NEVER DO THIS WITH A REAL KEY!!! | ||
PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" | ||
MY_ADDRESS="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" | ||
``` | ||
|
||
This is OK since the address and private key are well known testing keys. | ||
|
||
Then, you can run: | ||
|
||
```bash | ||
uv run deploy_favorites_unsafe.py # uv | ||
# or | ||
python deploy_favorites_unsafe.py # pip/python | ||
``` | ||
|
||
And you'll deploy the contract! | ||
|
||
## The Safer Way | ||
|
||
## 4. Encrypt your private key | ||
|
||
We want you to practice not having your private key in plain text! So run the following: | ||
|
||
```bash | ||
uv run encrypt_key.py # uv | ||
# or | ||
python encrypt_key.py # pip/python | ||
``` | ||
|
||
This will prompt you for a password and private key. We recommend using the following: | ||
|
||
``` | ||
0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 | ||
``` | ||
|
||
Since this is a well-known testing key, feel free to use an easy password - TYPICALLY YOU SHOULD NEVER SHARE YOUR PRIVATE KEY. | ||
|
||
### 5. Run the safe version | ||
|
||
```bash | ||
uv run deploy_favorites.py # uv | ||
# or | ||
python deploy_favorites.py # pip/python | ||
``` | ||
|
||
This will prompt you for a password to decrypt, and then you'll deploy your contract without exposing your private key! Huzzah! | ||
|
||
# Maintainer notes | ||
|
||
If you're a student, ignore this section! | ||
|
||
## Build a new requirements.txt | ||
|
||
```bash | ||
uv pip compile pyproject.toml -o requirements.txt | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
from web3 import Web3 | ||
from dotenv import load_dotenv | ||
from vyper import compile_code | ||
import os | ||
from encrypt_key import KEYSTORE_PATH | ||
from eth_account import Account | ||
import getpass | ||
|
||
load_dotenv() | ||
|
||
RPC_URL = os.getenv("RPC_URL") | ||
|
||
|
||
def main(): | ||
print("Let's read in the Vyper code and deploy it to the blockchain!") | ||
w3 = Web3(Web3.HTTPProvider(RPC_URL)) | ||
with open("favorites.vy", "r") as favorites_file: | ||
favorites_code = favorites_file.read() | ||
compliation_details = compile_code( | ||
favorites_code, output_formats=["bytecode", "abi"] | ||
) | ||
|
||
chain_id = 31337 # Make sure this matches your virtual network! | ||
|
||
print("Getting environment variables...") | ||
my_address = os.getenv("MY_ADDRESS") | ||
|
||
# private_key = os.getenv("PRIVATE_KEY") | ||
private_key = decrypt_key() | ||
|
||
# Create the contract in Python | ||
favorites_contract = w3.eth.contract( | ||
abi=compliation_details["abi"], bytecode=compliation_details["bytecode"] | ||
) | ||
|
||
# Submit the transaction that deploys the contract | ||
nonce = w3.eth.get_transaction_count(my_address) | ||
|
||
# We could do this next line as a shortcut :) | ||
# tx_hash = favorites_contract.constructor().transact() | ||
|
||
print("Building the transaction...") | ||
transaction = favorites_contract.constructor().build_transaction( | ||
{ | ||
"chainId": chain_id, | ||
# "gasPrice": w3.eth.gas_price, | ||
"gasPrice": 1, | ||
"from": my_address, | ||
"nonce": nonce, | ||
} | ||
) | ||
|
||
print("Signing transaction...") | ||
signed_txn = w3.eth.account.sign_transaction(transaction, private_key=private_key) | ||
print("We signed it, check it out:") | ||
print(signed_txn) | ||
|
||
print("Deploying Contract!") | ||
tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction) | ||
print("Waiting for transaction to finish...") | ||
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) | ||
print(f"Done! Contract deployed to {tx_receipt.contractAddress}") | ||
|
||
|
||
def decrypt_key() -> str: | ||
with open(KEYSTORE_PATH, "r") as fp: | ||
encrypted_account = fp.read() | ||
password = getpass.getpass("Enter your password for your keystore.json:\n") | ||
key = Account.decrypt(encrypted_account, password) | ||
print("Decrypted key!") | ||
return key | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
from web3 import Web3 | ||
from dotenv import load_dotenv | ||
from vyper import compile_code | ||
import os | ||
|
||
load_dotenv() | ||
|
||
RPC_URL = os.getenv("RPC_URL") | ||
|
||
|
||
def main(): | ||
print("Let's read in the Vyper code and deploy it to the blockchain!") | ||
w3 = Web3(Web3.HTTPProvider(RPC_URL)) | ||
with open("favorites.vy", "r") as favorites_file: | ||
favorites_code = favorites_file.read() | ||
compliation_details = compile_code( | ||
favorites_code, output_formats=["bytecode", "abi"] | ||
) | ||
|
||
chain_id = 31337 # Make sure this matches your virtual network! | ||
|
||
print("Getting environment variables...") | ||
my_address = os.getenv("MY_ADDRESS") | ||
private_key = os.getenv("PRIVATE_KEY") | ||
|
||
# Create the contract in Python | ||
favorites_contract = w3.eth.contract( | ||
abi=compliation_details["abi"], bytecode=compliation_details["bytecode"] | ||
) | ||
|
||
# Submit the transaction that deploys the contract | ||
nonce = w3.eth.get_transaction_count(my_address) | ||
|
||
# We could do this next line as a shortcut :) | ||
# tx_hash = favorites_contract.constructor().transact() | ||
|
||
print("Building the transaction...") | ||
transaction = favorites_contract.constructor().build_transaction( | ||
{ | ||
"chainId": chain_id, | ||
# "gasPrice": w3.eth.gas_price, | ||
"gasPrice": 1, | ||
"from": my_address, | ||
"nonce": nonce, | ||
} | ||
) | ||
|
||
print("Signing transaction...") | ||
signed_txn = w3.eth.account.sign_transaction(transaction, private_key=private_key) | ||
print("We signed it, check it out:") | ||
print(signed_txn) | ||
|
||
print("Deploying Contract!") | ||
tx_hash = w3.eth.send_raw_transaction(signed_txn.raw_transaction) | ||
print("Waiting for transaction to finish...") | ||
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) | ||
print(f"Done! Contract deployed to {tx_receipt.contractAddress}") | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from eth_account import Account | ||
import getpass | ||
from pathlib import Path | ||
import json | ||
|
||
KEYSTORE_PATH = Path(".keystore.json") | ||
|
||
|
||
def main(): | ||
# input for your private key | ||
private_key = getpass.getpass("Enter your private key:\n") | ||
my_account = Account.from_key(private_key) | ||
|
||
password = getpass.getpass("Enter a password:\n") | ||
encrypted_account = my_account.encrypt(password) | ||
|
||
print(f"Saving to {KEYSTORE_PATH}...") | ||
with KEYSTORE_PATH.open("w") as fp: | ||
json.dump(encrypted_account, fp) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# SPDX-License-Identifier: MIT | ||
# pragma version 0.4.0 | ||
|
||
my_favorite_number: uint256 | ||
|
||
struct Person: | ||
favorite_number: uint256 | ||
name: String[100] | ||
|
||
# Static Array/List | ||
list_of_people: public(Person[5]) | ||
list_of_people_index: uint256 | ||
|
||
name_to_favorite_number: HashMap[String[100], uint256] | ||
|
||
@external | ||
def store(favorite_number: uint256): | ||
self.my_favorite_number = favorite_number | ||
|
||
@external | ||
@view | ||
def retrieve() -> uint256: | ||
return self.my_favorite_number | ||
|
||
@external | ||
def add_person(name: String[100], favorite_number: uint256): | ||
new_person: Person = Person(favorite_number= favorite_number, name=name) | ||
self.list_of_people[self.list_of_people_index] = new_person | ||
self.list_of_people_index += 1 | ||
self.name_to_favorite_number[name] = favorite_number |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
def main(): | ||
print("Hello from web3py-simple-storage-cu!") | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[project] | ||
name = "web3py-simple-storage-cu" | ||
version = "0.1.0" | ||
description = "Add your description here" | ||
readme = "README.md" | ||
requires-python = ">=3.11" | ||
dependencies = [ | ||
"python-dotenv>=1.0.1", | ||
"vyper>=0.4.0", | ||
"web3>=7.2.0", | ||
] |
Oops, something went wrong.