# Završni ispit - ISBIT **Autori**: Bruno Grbac, Lorenzo Šamanić **Datum**: 30. siječanj 2023. **Predmet**: Informacijska sigurnost i blockchain tehnologije **Ak. god**: 2022./2023. **GitHub link**: https://github.com/BrunoG1121/ZavrsniIsbit # Sadržaj [ToC] # Uvod Napravljen je projektni zadatak za završni rad koristeći web3 modul za python te također kao dodatni zadatak koristeći web3js biblioteku. Stvoren je token "BrunoLorenzoToken" odnosno BLT u količini od 1 000 000 tokena. Kreirane su funkcije za mint i burn kao i prijenos s jedne adrese na drugu te provjera stanja prije i nakon transkacije. # Pametni ugovor Korišten je kompajler solidity 0.6.0 te su prvo definirane varijable owner, name, symbol, totalSupply i balanceOf ``` // SPDX-License-Identifier: MIT pragma solidity ^0.6.0; contract SimpleStorage { address public owner; string public name; string public symbol; uint256 public totalSupply; mapping (address => uint256) public balanceOf; ``` Definiran je konstruktor kojemu šaljemo adresu vlasnika, ime i simbol tokena te totalnu količinu tokena. Potom dodjeljujemo varijablama dobivene vrijednosti. ``` constructor(string memory _name, string memory _symbol, uint256 _totalSupply) public { owner = msg.sender; name = _name; symbol = _symbol; totalSupply = _totalSupply; balanceOf[msg.sender] = totalSupply; } ``` #### Funkcija Transfer Funkcija očekuje dobiti adresu na koju će se slati s vlasnikovog računa te samu vrijednost koja bi se trebala prebaciti. Ukoliko na računu vlasnika nema dovoljno tokena ispisuje se "Not enough balance". ``` function transfer(address _to, uint256 _value) public { require(balanceOf[msg.sender] >= _value, "Not enough balance"); balanceOf[msg.sender] -= _value; balanceOf[_to] += _value; } ``` #### Funkcija checkBalanceOf Funkcija očekuje dobiti adresu na kojoj će izvršiti provjeru te ispisati koliko se na adresi nalazi tokena. ``` function checkBalanceOf(address _owner) public view returns (uint256) { return balanceOf[_owner]; } ``` #### Funkcija mint Funkcija mint je funkcija koja kreira zadanu vrijednost tokena te ih pridodaje u dosadašnju totalnu količinu tokena koji postoje. Navedenu funkciju može koristiti samo vlasnik tokena. ``` function mint(uint256 _value) public { require(msg.sender == owner, "Only owner can mint"); totalSupply += _value; balanceOf[msg.sender] += _value; } ``` #### Funkcija burn Funkcija burn je funkcija koja briše zadanu vrijednost tokena te ih oduzima od dosadašnje totalne količine tokena koji postoje. Navedenu funkciju može koristiti samo vlasnik tokena te ne može izbrisati više tokena nego ih ima na računu vlasnika. ``` function burn(uint256 _value) public { require(msg.sender == owner, "Only owner can burn"); require(balanceOf[msg.sender] >= _value, "Not enough balance"); totalSupply -= _value; balanceOf[msg.sender] -= _value; } } ``` # Ganache testna mreža Prateći upute na GitHubu (https://github.com/trufflesuite/ganache) pokrenuta je ganache testna mreža u terminalu. ``` ganache v7.7.3 (@ganache/cli: 0.8.2, @ganache/core: 0.8.2) Starting RPC server Available Accounts ================== (0) 0xb918cA8Ce3d8B7055985Ccbe9e8308d9dffBb510 (1000 ETH) (1) 0xD18a1B693d585fBE721e1ADBa9351f75C5711F03 (1000 ETH) (2) 0xE3bC00cfd2060298438a3dA868063DBd52E96054 (1000 ETH) (3) 0x1Ee5198B49FcF72eC7b164411F2Fda11068450cc (1000 ETH) (4) 0xbfb7023B69F55C9b33de55740743f8631Ff6d454 (1000 ETH) (5) 0x54B5a6d4dc9E55fC01b153D445906b3d716c5BB2 (1000 ETH) (6) 0x35baeeaA1beec6609182a4eBFF6c632Ff6B527b7 (1000 ETH) (7) 0xdb7c146EdB5b30D57D2acd7615eD4232cb077861 (1000 ETH) (8) 0x1b48AaC0a47F852974c856eeE34ef2e5c996456A (1000 ETH) (9) 0x24e2e5b0048ff912B48983d428c9B3aF78476098 (1000 ETH) Private Keys ================== (0) 0x992d3738d6348fcafe885e012974011b711ffce04c0e75a6744df7c9db8c069e (1) 0xf837b4b08530ac4918c86a2dd9cf13785bf7a9b601d8b537c9188655ac904751 (2) 0x2205aae128eec61217c86ed5fb1fd38a51375b6fa81c163e5d7fb4f93ebe0d08 (3) 0xe26df98b35ca369715a4459bf02ef094b11c102774783a49bbf8d27086f86385 (4) 0x53aa64c002c515dc690467bf23f43bf2cc55f58522af31fd94a50dd2fd767aa0 (5) 0x925715e828ff7d48ed143ec94ddd64acc999e4d82b756a8ad6f5366709555921 (6) 0xd3f3691a59e54f0623d73aee04ad9ef8e45fb6b5585704b047b3a195a8388a80 (7) 0xc141df10408deb365a834530b430bd6ba3e62abbf49ba0e6c111639c8e767d9e (8) 0xe329a046799ceb9c4908d4c0fc7bc5ed83b036684d925701c99f3a3e2ed68d2f (9) 0xe8fde2401dcd98768621d78bf3fd62cecb52893c41728605f4d747ee4a2e6608 HD Wallet ================== Mnemonic: excuse section meat assault elite drop cousin van circle lock sing infant Base HD Path: m/44'/60'/0'/0/{account_index} Default Gas Price ================== 2000000000 BlockGas Limit ================== 30000000 Call Gas Limit ================== 50000000 Chain Id ================== 1337 ``` # web3 python Inicijalizacija odnosno dodavanje potrebnih biblioteka. ``` from solcx import compile_standard, install_solc # install_solc("0.6.0") import json from web3 import Web3 ``` Čitanje i kompaliranje pametnog ugovora SimpleStorage. ``` # Read the contents of the SimpleStorage.sol contract file with open("./SimpleStorage.sol", "r") as file: simple_storage_file = file.read() # Compile the Solidity contract using the solcx package compiled_sol = compile_standard( { "language": "Solidity", "sources": {"SimpleStorage.sol": {"content": simple_storage_file}}, "settings": { "outputSelection": { "*": {"*": ["abi", "metadata", "evm.bytecode", "evm.sourceMap"]} } }, }, solc_version="0.6.0", ) ``` Spremanje bytecode-a i ABI-a od pametnog ugovora te definiranje određenih parametara poput adrese vlasnika i njenog privatnog ključa. ``` # Save the compiled contract's bytecode and ABI to a local file with open("compiled_code.json", "w") as file: json.dump(compiled_sol, file) # Extract the bytecode and ABI from the compiled contract # bytecode bytecode = compiled_sol["contracts"]["SimpleStorage.sol"]["SimpleStorage"]["evm"][ "bytecode" ]["object"] # abi abi = compiled_sol["contracts"]["SimpleStorage.sol"]["SimpleStorage"]["abi"] w3 = Web3(Web3.HTTPProvider("http://127.0.0.1:8545")) chain_id = 1337 my_addres = "0x0056941d2d8e96Ff0c586c7AF2f8becc2f7c212a" private_key = "0x5def8119611261a8358c475f0d84c2f5c364954805cff7de8c95d766c08e83bd" ``` Kreiranje ugovora u pythonu te dobivanje nonce-a. ``` # Create the contract in python SimpleStorage = w3.eth.contract(abi=abi, bytecode=bytecode) # Get the nonce nonce = w3.eth.getTransactionCount(my_addres) ``` Definiranje imena, simbola i količine tokena koji će se generirati. Kreirali smo token BrunoLorenzoToken sa simbolom BLT te početnom količinom od 1 000 000 tokena. ``` # Build a transaction name = "BrunoLorenzoToken" symbol = "BLT" total_supply = 1000000 transaction = SimpleStorage.constructor(name, symbol, total_supply).buildTransaction( {"chainId": chain_id, "from": my_addres, "nonce": nonce} ) ``` Inicijaliziranje tokena. ``` # Sign a transaction signed_txn = w3.eth.account.sign_transaction(transaction, private_key=private_key) # Send the signed transaction tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction) tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash) contract_address = tx_receipt['contractAddress'] SimpleStorage2 = w3.eth.contract(address = contract_address, abi=abi) ``` Daljnje korišteni parametri. Količina koliko će se mintati i burnati, koja je druga adresa te broj tokena koje ćemo slati. ``` ###---Parametars---- mint_amount = 10 burn_amount = 500 Druga_adresa ="0x48B19a1EEA50Ee5D0bd782bd3CaC0617822E3679" BrojPoslanihTokena = 500 ###---------------- ``` Ispis totalnog broja tokena te broj tokena na vlasnikovom i drugom računu. ``` # Pregled pocetnog stanja print("----Pregled pocetnog stanja----") print("Initial total supply:", SimpleStorage2.functions.totalSupply().call()) balance2 = SimpleStorage2.functions.checkBalanceOf(my_addres).call() print("Stanje našeg računa(owner):", balance2) balance = SimpleStorage2.functions.checkBalanceOf(Druga_adresa).call() print("Stanje drugog računa:", balance) print("----------------------------") ``` Mintanje i burnanje tokena. ``` #Mintanje novih tokena SimpleStorage2.functions.mint(mint_amount).transact({'from': my_addres}) print("Total supply nakon mintanja:", SimpleStorage2.functions.totalSupply().call()) # Burnanje tokena SimpleStorage2.functions.burn(burn_amount).transact({'from': my_addres}) print("Total supply nakon burnanja:", SimpleStorage2.functions.totalSupply().call()) ``` Slanje s vlasnikovog računa na drugi račun koji je definiran u parametrima. ``` #Slanje s našeg računa na drugi print("---Slanje tokena s jednog računa na drugi---") balance2 = SimpleStorage2.functions.checkBalanceOf(my_addres).call() print("Stanje našeg računa:", balance2) balance = SimpleStorage2.functions.checkBalanceOf(Druga_adresa).call() print("Stanje drugog računa:", balance) SimpleStorage2.functions.transfer(Druga_adresa,BrojPoslanihTokena).transact({'from': my_addres}) print("Transfered") balance2 = SimpleStorage2.functions.checkBalanceOf(my_addres).call() print("Stanje našeg računa:", balance2) balance = SimpleStorage2.functions.checkBalanceOf(Druga_adresa).call() print("Stanje drugog računa:", balance) print("------------------------------------------") balance = w3.eth.getBalance(my_addres) ``` Ispis vlasnikovog stanja u etheriumu nakon svih transakcija kako bi vidjeli koliko je ETH-a potrošeno na gas fee. ``` # Convert the balance from wei to ether balance_ether = w3.fromWei(balance, 'ether') # Print the balance in ether print("Stanje ETH nakon odrađenih transakcija", my_addres, "je", balance_ether, "ether") ``` # Dodatni zadatak - web3js ## Sučelje: ![](https://i.imgur.com/eKIrwzE.png) ## Funkcije u index.js-u #### Funkcija SetupInitialContract Funkcija za kreiranje tokena gdje upisujemo naziv, simbol i količinu tokena kojeg želimo kreirati. ``` async function SetupInitialContract() { const myAddress = OwnerAddress; const constructorParams = [TokenN, TokenT, TokenS]; await SimpleStorage.deploy({ data: bytecode, arguments: constructorParams, }) .send({ from: myAddress, gas: "1000000", gasPrice: "1000000000", }) .then((newContractInstance) => { ContractInstance = newContractInstance console.log( `Contract deployed at address: ${newContractInstance.options.address}` ); }); } async function SolFunctions(){ await SetupInitialContract() } ``` #### Funkcija MintFunction Funkcija mintanja 100 tokena. ``` async function MintFunction(){ await ContractInstance.methods .mint(100) .send({ from: OwnerAddress, gas: "1000000", gasPrice: "1000000000", }) .then(() => { console.log("Mint transaction successful"); }); await ContractInstance.methods.totalSupply().call().then(function(result){TokenS= result}) } ``` #### Funkcija BurnFunction Funkcija burnanja 100 tokena. ``` async function BurnFunction(){ await ContractInstance.methods .burn(100) .send({ from: OwnerAddress, gas: "1000000", gasPrice: "1000000000", }) .then(() => { console.log("Burn transaction successful"); }); await ContractInstance.methods.totalSupply().call().then(function(result){TokenS= result}) } ``` #### Funkcija SendFunction Funkcija slanja u kojoj odabiremo adresu na koju se šalje te količinu tokena koju želimo poslati. ``` async function SendFunction(){ await ContractInstance.methods .transfer(SecAddress,SendAmount) .send({ from: OwnerAddress, gas: "1000000", gasPrice: "1000000000", }) .then(() => { console.log("Transfer succesful"); }); await ContractInstance.methods.totalSupply().call().then(function(result){TokenS= result}) } ``` #### Funkcija CheckFunction Funkcija provjere gdje odabiremo adresu na kojoj želimo provjeriti broj pohranjenih tokena. ``` async function CheckFunction(){ await ContractInstance.methods.checkBalanceOf(AddressToCheck).call().then(function(result){BalanceOfAcc = result}); await ContractInstance.methods.totalSupply().call().then(function(result){TokenS= result}) } ```