SC-02-Setup-Web3py-Python - Python et la Blockchain

<< Setup Foundry | Suivant : Solidity Basics >>


Objectifs d’apprentissage

  1. Installer et configurer web3.py pour interagir avec Ethereum depuis Python
  2. Installer py-solc-x pour compiler du Solidity depuis Python
  3. Se connecter a anvil (blockchain locale Foundry)
  4. Compiler, deployer et appeler un contrat Solidity entierement depuis Python
  5. Etablir le pattern reutilisable pour tous les notebooks suivants

Prerequis

Duree estimee : 40 minutes


1. Installation des dependances

Deux libraries essentielles : - web3.py : client Python pour Ethereum (deploiement, appels, events) - py-solc-x : wrapper Python autour du compilateur Solidity solc

# Installation (decommentez si necessaire)
# !pip install web3 py-solc-x

import importlib
for pkg in ["web3", "solcx"]:
    try:
        mod = importlib.import_module(pkg)
        version = getattr(mod, "__version__", "?")
        print(f"{pkg:10s} : v{version}")
    except ImportError:
        print(f"{pkg:10s} : NON INSTALLE - executez: pip install {'py-solc-x' if pkg == 'solcx' else pkg}")
web3       : v7.16.0
solcx      : v?

Installation du compilateur Solidity via py-solc-x pour permettre la compilation de contrats directement depuis Python.

# Installer le compilateur Solidity via py-solc-x
try:
    import solcx
except ImportError as e:
    print(f"Installation requise : pip install py-solc-x")
    print(f"Erreur : {e}")

# Installer la derniere version stable de solc
SOLC_VERSION = "0.8.28"
try:
    installed = solcx.get_installed_solc_versions()
    print(f"Versions solc installees : {installed}")
    if not any(str(v).startswith(SOLC_VERSION) for v in installed):
        print(f"Installation de solc {SOLC_VERSION}...")
        solcx.install_solc(SOLC_VERSION)
    solcx.set_solc_version(SOLC_VERSION)
    print(f"Compilateur actif : solc {solcx.get_solc_version()}")
except Exception as e:
    print(f"Erreur installation solc : {e}")
    print("Verifiez votre connexion internet et reessayez.")
Versions solc installees : [<Version('0.8.28')>]
Compilateur actif : solc 0.8.28

Interpretation : py-solc-x gere les binaires solc

py-solc-x telecharge et gere les binaires solc automatiquement. Cela nous permet de compiler du Solidity directement depuis Python, sans avoir besoin d’un IDE comme Remix ou d’un framework comme Hardhat.


2. Connexion a anvil (blockchain locale)

anvil est le noeud Ethereum local de Foundry. Il simule une blockchain complete en memoire avec 10 comptes pre-finances (10 000 ETH chacun).

Demarrer anvil

Dans un terminal separe, lancez :

anvil

Anvil ecoute par defaut sur http://127.0.0.1:8545.

try:
    from web3 import Web3
except ImportError as e:
    print(f"Installation requise : pip install web3")
    print(f"Erreur : {e}")

# Connexion a anvil (blockchain locale)
ANVIL_URL = "http://127.0.0.1:8545"
w3 = Web3(Web3.HTTPProvider(ANVIL_URL))

if w3.is_connected():
    print(f"Connecte a : {ANVIL_URL}")
    print(f"Chain ID   : {w3.eth.chain_id}")
    print(f"Bloc actuel: {w3.eth.block_number}")
    print(f"Gas price  : {w3.eth.gas_price} wei")
    print()

    # Comptes disponibles (pre-finances par anvil)
    accounts = w3.eth.accounts
    print(f"Comptes disponibles : {len(accounts)}")
    for i, account in enumerate(accounts[:3]):
        balance = w3.eth.get_balance(account)
        print(f"  [{i}] {account} : {w3.from_wei(balance, 'ether'):.0f} ETH")
    print(f"  ... ({len(accounts) - 3} autres comptes)")
else:
    print(f"ERREUR : Impossible de se connecter a {ANVIL_URL}")
    print("Avez-vous lance 'anvil' dans un terminal separe ?")
Connecte a : http://127.0.0.1:8545
Chain ID   : 31337
Bloc actuel: 0
Gas price  : 2000000000 wei

Comptes disponibles : 10
  [0] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 : 10000 ETH
  [1] 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 : 10000 ETH
  [2] 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC : 10000 ETH
  ... (7 autres comptes)

Interpretation : anvil, un environnement de test gratuit et instantane

Anvil fournit un environnement de test gratuit et instantane : - Pas besoin de vrais ETH (comptes pre-finances) - Blocs mines instantanement (pas d’attente) - Etat reinitialise a chaque redemarrage - Compatible avec tous les outils Ethereum (web3.py, ethers.js, Metamask)

C’est l’equivalent d’un Ganache modernise, integre a Foundry.


3. Compiler un contrat Solidity depuis Python

Avec py-solc-x, on compile du Solidity et on recupere l’ABI (interface) et le bytecode.

import solcx

# Contrat Solidity simple
HELLO_SOL = """
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

contract Hello {
    string public message;

    constructor(string memory _message) {
        message = _message;
    }

    function setMessage(string memory _message) public {
        message = _message;
    }

    function getMessage() public view returns (string memory) {
        return message;
    }
}
"""

# Compilation
compiled = solcx.compile_source(
    HELLO_SOL,
    output_values=["abi", "bin"],
    solc_version=SOLC_VERSION,
)

# Extraire le contrat compile
contract_id, contract_interface = compiled.popitem()
abi = contract_interface["abi"]
bytecode = contract_interface["bin"]

print(f"Contrat compile : {contract_id}")
print(f"ABI : {len(abi)} fonctions/events")
for item in abi:
    kind = item.get("type", "?")
    name = item.get("name", "(constructor)" if kind == "constructor" else "?")
    print(f"  {kind:12s} : {name}")
print(f"Bytecode : {len(bytecode)} hex chars ({len(bytecode)//2} bytes)")
Contrat compile : <stdin>:Hello
ABI : 4 fonctions/events
  constructor  : (constructor)
  function     : getMessage
  function     : message
  function     : setMessage
Bytecode : 5976 hex chars (2988 bytes)

Interpretation : les deux artefacts de la compilation, ABI et bytecode

La compilation produit deux artefacts essentiels :

Artefact Rôle
ABI (Application Binary Interface) Decrit les fonctions du contrat (noms, types, paramètres)
Bytecode Le code machine EVM, deploye sur la blockchain

L’ABI est necessaire pour interagir avec le contrat après deploiement. Le bytecode est envoye dans une transaction de creation de contrat.


4. Deployer le contrat sur anvil

Le deploiement envoie le bytecode dans une transaction speciale (sans destinataire). Le contrat reçoit alors une adresse sur la blockchain.

# Deploiement du contrat Hello
Hello = w3.eth.contract(abi=abi, bytecode=bytecode)

# Compte deployer (premier compte anvil)
deployer = w3.eth.accounts[0]

# Construire et envoyer la transaction de deploiement
tx_hash = Hello.constructor("Bonjour depuis Python !").transact({
    "from": deployer,
})

# Attendre la confirmation
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)

contract_address = tx_receipt.contractAddress
print(f"Contrat deploye !")
print(f"  Adresse    : {contract_address}")
print(f"  Tx hash    : {tx_hash.hex()}")
print(f"  Bloc       : {tx_receipt.blockNumber}")
print(f"  Gas utilise: {tx_receipt.gasUsed:,}")
Contrat deploye !
  Adresse    : 0x5FbDB2315678afecb367f032d93F642f64180aa3
  Tx hash    : 3eebd7e74e237341a518c14ae447ed4bb5fe2de9ae6dcd27114c2a961fc6b98f
  Bloc       : 1
  Gas utilise: 476,957

Interpretation : un contrat deploye, adresse, code et etat

Le contrat est maintenant vivant sur la blockchain locale. Il a : - Une adresse unique (hash de l’adresse du deployeur + nonce) - Son code stocke dans la blockchain (le bytecode) - Son etat initialise (la variable message = “Bonjour depuis Python !”)

Toute interaction future se fera via cette adresse.


5. Interagir avec le contrat

Deux types d’appels : - call() : lecture seule (gratuit, pas de transaction) - transact() : modification d’etat (consomme du gas, créé une transaction)

# Creer une instance du contrat a son adresse
hello = w3.eth.contract(address=contract_address, abi=abi)

# LECTURE : appeler getMessage() (gratuit, pas de gas)
message = hello.functions.getMessage().call()
print(f"Message actuel : '{message}'")
print()

# ECRITURE : appeler setMessage() (transaction, consomme du gas)
tx_hash = hello.functions.setMessage("Hello from web3.py !").transact({
    "from": deployer,
})
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print(f"setMessage() execute :")
print(f"  Gas utilise : {receipt.gasUsed:,}")
print(f"  Status      : {'OK' if receipt.status == 1 else 'ECHEC'}")
print()

# Relire le message
new_message = hello.functions.getMessage().call()
print(f"Nouveau message : '{new_message}'")
print()

# On peut aussi lire la variable publique directement
direct = hello.functions.message().call()
print(f"Lecture directe : '{direct}'")
assert direct == new_message, "Les deux lectures doivent etre identiques"
Message actuel : 'Bonjour depuis Python !'

setMessage() execute :
  Gas utilise : 28,234
  Status      : OK

Nouveau message : 'Hello from web3.py !'

Lecture directe : 'Hello from web3.py !'

Interpretation : call() et transact(), gas et etat

Opération Méthode Gas Modifie l’etat
Lecture .call() 0 Non
Ecriture .transact() > 0 Oui

Les variables public generent automatiquement un getter (ici message()). C’est pourquoi getMessage() et message() retournent la même valeur.


6. Pattern helper reutilisable

Pour les notebooks suivants, nous utiliserons un helper qui encapsule la connexion, la compilation et le deploiement en quelques lignes.

def compile_and_deploy(w3, source_code, deployer, *constructor_args):
    """Compiler et deployer un contrat Solidity en une seule fonction.

    Args:
        w3: Instance Web3 connectee
        source_code: Code Solidity complet
        deployer: Adresse du compte deployeur
        *constructor_args: Arguments du constructeur

    Returns:
        tuple: (contract_instance, tx_receipt)
    """
    import solcx

    # Compiler
    compiled = solcx.compile_source(
        source_code,
        output_values=["abi", "bin"],
        solc_version=SOLC_VERSION,
    )
    contract_id, contract_interface = compiled.popitem()
    abi = contract_interface["abi"]
    bytecode = contract_interface["bin"]

    # Deployer
    Contract = w3.eth.contract(abi=abi, bytecode=bytecode)
    tx_hash = Contract.constructor(*constructor_args).transact({"from": deployer})
    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)

    # Retourner l'instance du contrat
    instance = w3.eth.contract(address=receipt.contractAddress, abi=abi)
    return instance, receipt


# Test du helper avec un contrat Counter
COUNTER_SOL = """
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

contract Counter {
    uint256 public count;

    function increment() public {
        count += 1;
    }

    function decrement() public {
        require(count > 0, "Cannot go below zero");
        count -= 1;
    }
}
"""

counter, receipt = compile_and_deploy(w3, COUNTER_SOL, deployer)
print(f"Counter deploye a : {counter.address}")
print(f"Gas: {receipt.gasUsed:,}")
print()

# Utilisation
print(f"count = {counter.functions.count().call()}")

for i in range(5):
    counter.functions.increment().transact({"from": deployer})
print(f"Apres 5 increments : count = {counter.functions.count().call()}")

counter.functions.decrement().transact({"from": deployer})
print(f"Apres 1 decrement  : count = {counter.functions.count().call()}")
Counter deploye a : 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0
Gas: 184,481

count = 0
Apres 5 increments : count = 5
Apres 1 decrement  : count = 4

Interpretation : un helper de deploiement reutilisable

Le helper compile_and_deploy() sera reutilise dans tous les notebooks suivants. Il reduit le deploiement a une seule ligne :

contract, receipt = compile_and_deploy(w3, SOLIDITY_CODE, deployer)

Cela nous permet de nous concentrer sur le code Solidity et les interactions, plutot que sur la plomberie de compilation/deploiement.


7. Transactions multi-comptes

Anvil fournit 10 comptes pre-finances. Cela permet de simuler des interactions entre plusieurs utilisateurs (votes, transfers, encheres).

# Simuler un transfert d'ETH entre comptes
alice = w3.eth.accounts[0]
bob = w3.eth.accounts[1]

# Soldes avant
balance_alice_before = w3.eth.get_balance(alice)
balance_bob_before = w3.eth.get_balance(bob)

# Transfert de 1 ETH
tx_hash = w3.eth.send_transaction({
    "from": alice,
    "to": bob,
    "value": w3.to_wei(1, "ether"),
})
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)

# Soldes apres
balance_alice_after = w3.eth.get_balance(alice)
balance_bob_after = w3.eth.get_balance(bob)

print("TRANSFERT ETH")
print("=" * 60)
print(f"Alice ({alice[:10]}...) :")
print(f"  Avant : {w3.from_wei(balance_alice_before, 'ether'):.4f} ETH")
print(f"  Apres : {w3.from_wei(balance_alice_after, 'ether'):.4f} ETH")
print(f"  (envoye 1 ETH + gas)")
print()
print(f"Bob ({bob[:10]}...) :")
print(f"  Avant : {w3.from_wei(balance_bob_before, 'ether'):.4f} ETH")
print(f"  Apres : {w3.from_wei(balance_bob_after, 'ether'):.4f} ETH")
print(f"  (recu 1 ETH)")
print()
print(f"Gas utilise : {receipt.gasUsed:,} ({w3.from_wei(receipt.gasUsed * receipt.effectiveGasPrice, 'ether'):.6f} ETH)")
TRANSFERT ETH
============================================================
Alice (0xf39Fd6e5...) :
  Avant : 9999.9984 ETH
  Apres : 9998.9984 ETH
  (envoye 1 ETH + gas)

Bob (0x70997970...) :
  Avant : 10000.0000 ETH
  Apres : 10001.0000 ETH
  (recu 1 ETH)

Gas utilise : 21,000 (0.000027 ETH)

8. Exemple guide : Deployer et tester un contrat Vault

Resolu par le groupe Antoine Gaillard & Ambroise Durst (contribution PR #2397).

Compilez, deployez et testez un coffre-fort Solidity depuis Python.

# Exercice : Contrat Vault (coffre-fort)
VAULT_SOL = """
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

contract Vault {
    mapping(address => uint256) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) public {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        balances[msg.sender] -= amount;
        payable(msg.sender).transfer(amount);
    }

    function getBalance() public view returns (uint256) {
        return balances[msg.sender];
    }
}
"""

# Verifier la connexion a anvil avant de deployer
if not w3.is_connected():
    raise ConnectionError(
        "Impossible de se connecter a anvil sur http://127.0.0.1:8545. "
        "Lancez `anvil` dans un terminal separe puis relancez cette cellule."
    )

# Deployer le contrat Vault
vault, receipt = compile_and_deploy(w3, VAULT_SOL, deployer)
print(f"Vault deploye a : {vault.address}")
print(f"Gas de deploiement : {receipt.gasUsed:,}")
print()

# Comptes Alice et Bob
alice = w3.eth.accounts[1]
bob = w3.eth.accounts[2]

# Deposer 2 ETH depuis Alice
print("Depot 2 ETH depuis Alice")
tx_hash = vault.functions.deposit().transact({
    "from": alice,
    "value": w3.to_wei(2, "ether"),
})
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print(f"  Tx hash : {tx_hash.hex()}")
print(f"  Gas utilise : {receipt.gasUsed:,}")
print()

# Deposer 1 ETH depuis Bob
print("Depot 1 ETH depuis Bob")
tx_hash = vault.functions.deposit().transact({
    "from": bob,
    "value": w3.to_wei(1, "ether"),
})
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print(f"  Tx hash : {tx_hash.hex()}")
print(f"  Gas utilise : {receipt.gasUsed:,}")
print()

# Verifier les soldes dans le vault
balance_alice = vault.functions.getBalance().call({"from": alice})
balance_bob = vault.functions.getBalance().call({"from": bob})
print("Soldes dans le vault :")
print(f"  Alice : {w3.from_wei(balance_alice, 'ether'):.3f} ETH")
print(f"  Bob   : {w3.from_wei(balance_bob, 'ether'):.3f} ETH")
print()

# Alice retire 0.5 ETH
print("Alice retire 0.5 ETH")
tx_hash = vault.functions.withdraw(w3.to_wei(0.5, "ether")).transact({
    "from": alice,
})
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print(f"  Tx hash : {tx_hash.hex()}")
print(f"  Gas utilise : {receipt.gasUsed:,}")
print()

# Verifier le solde final d'Alice
final_balance_alice = vault.functions.getBalance().call({"from": alice})
print("Solde final d'Alice dans le vault :")
print(f"  Alice : {w3.from_wei(final_balance_alice, 'ether'):.3f} ETH")
assert final_balance_alice == w3.to_wei(1.5, "ether"), "Le solde final d'Alice doit etre 1.5 ETH"
print("Verification : le solde final d'Alice est bien 1.5 ETH")
Vault deploye a : 0x610178dA211FEF7D417bC0e6FeD39F05609AD788
Gas de deploiement : 325,118

Depot 2 ETH depuis Alice
  Tx hash : 3ae6f559b30f6d24ce9d62e82bb8fb81c39181a15ceab4e2d6a55b6b346d3688
  Gas utilise : 43,623

Depot 1 ETH depuis Bob
  Tx hash : 52428b2b8f9d6805cd0dd3523838c2afaa8d95e9317539c94e5273a78b02fc23
  Gas utilise : 43,623

Soldes dans le vault :
  Alice : 2.000 ETH
  Bob   : 1.000 ETH

Alice retire 0.5 ETH
  Tx hash : d835f309d9effe485207e76f5b7ab73ba9770f358ae2b9cfe18df30fa9f45324
  Gas utilise : 34,098

Solde final d'Alice dans le vault :
  Alice : 1.500 ETH
Verification : le solde final d'Alice est bien 1.5 ETH

Exercice (a completer) : Événements et plafond de depot

En vous inspirant de l’exemple guide ci-dessus, faites evoluer le contrat Vault :

  1. Ajoutez deux événements Solidity Deposit(address indexed compte, uint256 montant) et Withdrawal(address indexed compte, uint256 montant), et emettez-les dans deposit() et withdraw().
  2. Ajoutez un plafond : refusez (require) tout depot qui ferait depasser un solde individuel de 5 ETH.
  3. Redeployez le contrat, effectuez un depot valide puis un depot qui depasse le plafond (attrapez l’exception), et lisez les événements via contract.events.Deposit().get_logs(...).
# Exercice : Evenements et plafond de depot sur le contrat Vault
# TODO etudiant :
#   Etape 1 : copier VAULT_SOL et ajouter les evenements Deposit / Withdrawal + le plafond (require <= 5 ETH)
#   Etape 2 : recompiler et redeployer avec compile_and_deploy(w3, VAULT_PLAFOND_SOL, deployer)
#   Etape 3 : tester un depot valide, puis un depot au-dela du plafond (try/except)
#   Etape 4 : lire les evenements emis via vault.events.Deposit().get_logs(from_block=0)

print("Exercice a completer")
Exercice a completer

Exercice (a completer) : Protection anti-reentrance sur le contrat Vault

Le contrat Vault de l’exemple guide (cellule precedente) presente une faille classique de reentrance : dans withdraw(), le transfert ETH vers l’appelant (payable(...).transfer(amount)) intervient avant la mise a jour du solde, ce qui permet a un contrat malveillant de rappeler withdraw() pendant le transfert et de vider les fonds.

Objectif : appliquer le pattern Checks-Effects-Interactions via un guard de reentrance.

  1. Ajoutez une variable d’etat bool public locked; (initialement false).
  2. Definissez un modifier nonReentrant qui reverte si locked est true, pose le verrou avant l’effet, et le relache apres : require(!locked, "Reentrant"); locked = true; _; locked = false;.
  3. Appliquez nonReentrant a deposit() et withdraw().
  4. Redeployez avec compile_and_deploy(w3, VAULT_REENTRANCY_SOL, deployer) puis verifiez qu’une deuxieme appel imbrique est bien bloque (scenario de test).

Indice : l’ordre Checks -> Effects (mise a jour de balances) -> Interactions (transfer) est tout aussi important que le guard lui-meme ; le modifier protege, l’ordre elimine la race.

# Exercice : Protection anti-reentrance sur le contrat Vault
# TODO etudiant :
#   Etape 1 : copier VAULT_PLAFOND_SOL (ou VAULT_SOL) et ajouter un guard de reentrance
#             - variable d'etat bool locked (init a false)
#             - modifier nonReentrant { require(!locked, "Reentrant"); locked = true; _; locked = false; }
#             - appliquer nonReentrant a deposit() et withdraw()
#   Etape 2 : recompiler et redeployer avec compile_and_deploy(w3, VAULT_REENTRANCY_SOL, deployer)
#   Etape 3 : verifier que le guard bloque une tentative de reentrance (scenario de test)
print("Exercice a completer")
Exercice a completer

Exercice (a completer) : call() vs transact() – lecture vs ecriture

Web3.py distingue deux modes d’interaction avec un contrat deploye, et la confusion entre les deux est une source frequentes de bugs. Cet exercice vise a bien ancrer la difference.

  1. Ecrivez un contrat LectureEcriture qui stocke un uint256 public valeur; et expose :
    • une fonction view getValeur() returns (uint256) (lecture seule, hors frais),
    • une fonction write setValeur(uint256 v) (modifie l’etat, coute du gas).
  2. Deployez avec compile_and_deploy(w3, LECTURE_ECRITURE_SOL, deployer).
  3. Lisez la valeur initiale via .call() (transaction simulee, pas de gas, pas de modification d’etat – c’est l’equivalent d’un eth_call).
  4. Modifiez la valeur via .transact() (transaction reelle minee, coute du gas, modifie l’etat – equivalent d’un eth_sendTransaction).
  5. Relisez via .call() pour confirmer que l’etat a change.

Indice : une fonction marquee view ou pure en Solidity peut etre appelee gratuitement via .call() ; toute fonction qui ecrit ne peut l’etre que via .transact(). Confondre les deux sur une fonction d’ecriture = la transaction echoue silencieusement (pas d’effet) ou est rejectee.

# Exercice : call() vs transact() -- lecture (view) vs ecriture (state change)
# TODO etudiant :
#   Etape 1 : ecrire un contrat LectureEcriture avec une fonction view getValeur() et une fonction setValeur(uint256 v)
#   Etape 2 : deployer via compile_and_deploy(w3, LECTURE_ECRITURE_SOL, deployer)
#   Etape 3 : lire la valeur initiale avec .call() (pas de gas, pas de modification d'etat)
#   Etape 4 : modifier la valeur avec .transact() (coute du gas, modifie l'etat)
#   Etape 5 : relire via .call() pour confirmer le changement d'etat
print("Exercice a completer")
Exercice a completer

9. Resume : outils et pattern reutilisable

Outil Rôle Commande
web3.py Client Python Ethereum pip install web3
py-solc-x Compilateur Solidity pip install py-solc-x
anvil Blockchain locale anvil (terminal)
solcx API de compilation solcx.compile_source()

Pattern pour les notebooks suivants

from web3 import Web3
import solcx

w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))
deployer = w3.eth.accounts[0]

contract, receipt = compile_and_deploy(w3, SOLIDITY_CODE, deployer)
result = contract.functions.myFunction().call()
contract.functions.myFunction(arg).transact({'from': deployer})

Notebook suivant : SC-03-Solidity-Basics-Python - Types, variables et structures Solidity (avec deploiement reel)

Conclusion et perspectives

Ce notebook a etabli le pont entre Python et la blockchain en configurant les deux outils essentiels du workflow de développement : web3.py pour interagir avec Ethereum et py-solc-x pour compiler du Solidity directement depuis Python. Le parcours complet – compilation d’un contrat source Solidity en ABI et bytecode, deploiement via transaction sur le noeud local anvil, puis interactions en lecture (.call()) et en ecriture (.transact()) – constitue le pattern reutilisable qui servira de base a tous les notebooks suivants de la serie.

Le helper compile_and_deploy() encapsule toute la complexite de compilation et deploiement en un seul appel, permettant de se concentrer sur la logique Solidity plutot que sur la plomberie. La demonstration des transactions multi-comptes avec transfert d’ETH entre Alice et Bob a illustre le modèle de gas et la différence entre opérations de lecture (gratuites) et d’ecriture (consommant du gas). L’exercice du contrat Vault introduit les mappings et le pattern payable qui seront approfondis dans les notebooks suivants.

Avec cet environnement operationnel, le notebook suivant SC-03-Solidity-Basics-Python entre dans le coeur du langage Solidity en explorant les types de données (bool, uint, int, address, bytes, string), les variables d’etat et locales, et les conversions de types, le tout compile et deploye reellement sur anvil.


<< Setup Foundry | Suivant : Solidity Basics >>

Retour au sommet