SOLIDITY

INTRO

Solidity is a contract-oriented, high-level language for implementing smart contracts. It's a statically typed language similar to object oriented languages. It was influenced by C++, Python and JavaScript and is designed to insert the smart contracts into Ethereum Virtual Machine (EVM) and executed on the Ethereum blockchain network. The best way to try the Solidity language is Remix a web browser storage at the following link https://remix.ethereum.org. Into the Remix application you can compile, run and debug your solidity program before you insert it into ethereum network. Verificare costantemente le novità essendo un nuovo linguaggio e la blockchain in continua evoluzione ci sono sempre nuove versioni del compilatore.

Schema of solidity program

pragma solidity ^0.4.6; //version of the compilator

contract name { //CapitalizeWords

state/storage variables //store into the chain

events/log //prodotti dal contratto

functions //se recupero di un dato = 0 Gas ma se modifica dei dati si paga Gas

}

CONTRACT

In un programma possiamo inserire più contracts
I contract possono essere creati, importati o ereditati
Vediamo un esempio di come importare un contract e un caso di inheritance
import "./A.sol"; //import contract anche da Http o GitHub

contract B is A { Inheritance
....
....
}

VARIABILI

Possiamo definire variabili

BOOLEAN (bool true/false)
Operatori
- ! Negazione logica
- && And
- || OR
- == uguale
- != diverso

NUMERI integer int e uint(unsigned integer solo numeri positivi) di diverse dimensioni int8, int16, int32 o uint8, uint16, uint32 di Default(int o uint) int256 o uint256

Operatori:
Comparisons: <=, <, ==, !=, >=, > (evaluate to bool)
Bit operators: &, |, ^ (bitwise exclusive or), ~ (bitwise negation)
Shift operators: << (left shift), >> (right shift)
Arithmetic operators: +, -, unary -, *, /, % (modulo), ** (exponentiation)

BYTES e STRING

Si può definire un array bytes ma è possibile utilizzare byte1, byte2, byte3 fino a byte32. Si può memorizzare testo e byte e usando meno gas il costo è minore ma le variabili byte ono limitate a 32 caratteri. per cui per testo di lunghezza maggiore necessario usare string.
STATIC

byte[10] dinArray; //static byte array
bytes1 test1;
bytes32 testbytesmax;
bytes32 mese = "July";
fixbyte = [byte(1),2,3]; //uint8 convert to byte explicit

DYNAMIC

bytes[] = bytes1[32]
byte[] testbytes; //dynamic byte array
bytes bitData; //no bitData = [byte(1),2,3,4] permesso solo bitData[0] = 1
din1 = new byte[](5);
din1 = [byte(1),2,3,4];
din1[2] = 20; //assegnazione valore diverso da quello iniziale
din1.length = 10; //modifica lunghezza
STRING

No lunghezza fissa - No accesso con indice - No aumentare con push
Per verificare lunghezza string > zero
- if (bytes(stringa).length == 0 {}) string previsione = "Le previsioni del tempo della prossima settimana non sono buone";
string din = string(bytesArray); //convert bytes into string
string din1 = string(bytes32Array);
bytess arr2 = bytes(din); //convert string into bytes
ADDRESS 20 byte Ethereum address //indirizzo token
Per verificare il valore di una variabile non c'è ne null or undefined come in JavaScript ma ci sono altri metodi che dipendono dal tipo di variabile
Verifica se variabile è di tipo address e se array è vuoto
pragma solidity ^0.4.17 ;
contract Test {

uint[] myArray;

function checktype() public view returns(bool, bool) {
//check type address
bool check;
address titolare ;
check = ( titolare == address(0x0));

//check type array
bool ArrayEmpty;
ArrayEmpty = (myArray.length == 0);

return (check, ArrayEmpty) ;
}
}

ADDRESS

La variabile Address è specifica del linguaggio Solidity e viene usata per identificare i token usati nella blockchain Ethereum. Per questo ha delle funzioni specifiche per lo scambio e la visualizzazione del valore che ogni token incorpora.
Vediamo queste funzioni nel dettaglio.
BALANCE address.balance() restituisce il saldo del wallet associato all'indirizzo in wei nella rete ethereum associata sia essa di test che la blockchain effettiva

address.transfer(10) or address.send(20) -- trasferiscono rispettivamente 10 e 20 wei
SEND/TRANSFER

- sender - receiver
address.send()
address.transfer() send can fail
1. Payable fallback function runs out of gas
2. Payable function runs out of gas
3. Payable function throws exception
address.send()
• Returns false on failure but it does not HALT contract execution
address.transfer()
• Throws exception on failure; HALTs the execution
Operatori:
<=, <, ==, !=, >= e >

TYPE CONVERSION

implicit - controllato dal compilatore
explicit - usare con cautela perchè possibilità di perdita dei dati, se compatibilità compilatore non controlla e tronca i dati che eccedono le dimensione ad esempio se passo una variabile int16 a int8

DATA ALLOCATION

STORAGE
persistent memory(database) key/value it is store. Quando operazioni di read or write pagare una fee
Contract can manage only its own for security.
In storage viene salvato lo stato delle variabili, local variables, argoments delle function se indicato es. function A(c uint storage, d int, e bool storage)
c and e saved in storage perchè indicato
MEMORY
memoria temporanea dei dati usati all'interno della function

es:
int number; storage
function A(number) {
num = number
}
number definito in storage mentre num crea una copia in memory di number che viene eliminata una volta terminata l'elaborazione
Si può definire una variabile in memory con una referenza ad una variabile definita in storage es.
int casa
function a () {
int b = a
}

CALLDATA Temporanea allocazione di variabili di funzioni esterne.

ARRAY

array può essere static o dynamic
STATIC ARRAY definita la lunghezza nel momento della creazione
int[10] MyArray; //array di 10 elementi

DYNAMIC ARRAY lunghezza non definita per cui si possono inserire nuovi elementi

dynamicBoolArray = new bool[](5) //definizione di array dynamic di 5 elementi
dynamicInt = [5,int16(4),3] //inizializzazione implicita da uint8 a int16
int[] array; //Storage se fatto in memory si ha un errore
MyArray2 = new int[](10); //definiziono nuovo array
MyArray.push(5); //add nuovo elemento
MyArray = [10,20,35];
MyArray.pop(0) //delete elementi
MyArray.lenght //numero elementi

MAPPING

Mapping è in particolare data type, è hashtable come struct, allocato solo nello storage o state variable ed è composto da dati nella forma Key/value e può contenere al suo interno altre mapping ma non come Key
Key value pussono essere tutti i tipi di dati tranne i mapping
mapping(bytes32 = bytes32) person // definizione mapping person
mapping(address = uint) listaToken //lista address con relativo saldo
person['Rossi'] //Risultato Mario
mapping (string = mapping (string = uint256)) abitanti;//mapping regione/città/abitanti
abitanti['Lazio']['Roma'] ;//Risultato numero abitanti di Roma
key può essere cryptografied con keccak256(key data)
Una limitazione è che non è possibile iterare il mapping ad esempio con un ciclo for come per un array perchè l'accesso è consentito solo con la key.
Inoltre non ha la funzione lenght per sapere quanti elementi compongono il mapping
ITERATION on MAPPING

insert new data into array address automatic to mapping
if i do address.lenght i have the lenght of mapping
mapping(address => bytes32) addressMAp;
address[] addressess;

STRUCT


Una Struct può essere equiparata ad un oggetto di JavaScript in qunìanto si compone di diversi componenti.
Non può contenere al suo interno un'altra struct ma può essere contenuta in un array o mapping.
pragma solidity 0.4.17 ;

contract Test {
struct MyStruc {
address myadd;
bytes description;
uint saldo;
}

MyStruc lista;

address add;
bytes description;
uint sal;

function esstruct(address add, bytes32 description, uint sal ) public {
lista = MyStruc(add, description, sal);//copia in STORAGE
}

}
Ora vediamo un esempio di Struct con una reference alla struct definita in storage e poi utilizzata per aggiungere dati in local all'interno di una function con il comando localReference che non crea una copia in storage ma update la struct in storage.
pragma solidity 0.4.17 ;

contract Test {

struct MyStruc {
address myadd;
bytes description;
uint saldo;
}

MyStruc lista;

function esstruct(address add, bytes description, uint sal ) public {
MyStruc storage localReference = lista;//UPDATE in STORAGE

localReference.myadd = add;
localReference.description = description;
localReference.saldo = sal;
}
}

ENUMS

Creare custom data types con un limitato set di valori.
Non viene inserito nella ABI defination.
Conversione dati solo in modo explicito.
enums City {
Rome;
Paris;
}

FUNCTION

Le Function vanno definite con un nome, gli eventuali arguments(data type nome arguments) e se ci si aspetta un output va inserita la leyword returns ed il tipo di dato atteso e se si vuole si può inserire il nome della variabile. Sotto lo schema di una function
function A(tipo dato nome_variabile) returns(define return named returned automatic)

Se l'output è costituito da più variabili ritorna una tupla(con differenti tipi di dati)

Tuple definita con var è una lista di oggetti per contenere i results di una function
Esempio di tupla: var(a, b, c)=getTuple(); è possibile non inserire una o più es var(a,b, )=getTuple();

All'interno di una function una variabile definita non può essere ridefinita e se non inizializzata un byte viene di default inizializzato con value 0s mentre una variabile booleana con False.

Solidity accetta la function overloading, la possibilità di definire diverse funzioni con lo stesso nome ma che accettano arguments diversi, il compilatore verifica dal contesto quale funzione si vuole richiamare.
function funOver() returns (int) {
int a = 5;
return a ;
}
function funOver(int b , int c ) returns (int) {

return b + c ;
}

INHERITANCE - MULTIPLE INHERITANCE

Abstract Contract there are no keyword for abstract contracts
the functions declared but no body provided -- view the example below:

function a(uint b){ }

MULTIPLE INHERITANCE
the multiple inheritance permit import most contract but only a single contract it is created
- view the example below:
inheritance contract
import a.sol
import b.sol
contract c is a,b {
}
if function are inserted into contract imported(a or b) its must be declared in new contract created.

CONSTRUCTOR

Constructor è una funzione speciale che permette di inizializzare lo state variables di un contract.
Può essere public or internal ed in questo caso vuol dire che il contract è abstract.
Se non inseriamo il construct nel nostro programma viene inserito in automatico dal compilatore.
Viene eseguito quando il contract viene creato ed ogni contract può avere un solo constructor.
Dopo l'esecuzione il codice prodotto viene inserito nella blockchain.

pragma solidity 0.6.4;

contract Test {
constructor() public {}
}

VISIBILITY

Le function possono essere richiamate da altri ocntracts per cui è bene specificare quali possono essere richiamate da altri contract oppure no. Per questo sono previste le istruzioni seguenti : public private | internal external
PUBLIC è di default per le function e può essere utilizzato per le variabili ora che sappiamo che la function o variable is public dobbiamo indicare se è internal o external
Se per la function mettiamo external può essere richiamata ed eseguita da altro contract altrimenti no. Quindi per non farla eseguire bisogna mettere internal.
INTERNAL
- è di default per le varibili nello storage
- Not in ABI
- function e variabili disponibili nei contratti derivati
EXTERNAL
- non disponibile per le variabili
- non richiamabili all'interno di altre function come una funzione normale
- bisogna inserire la keyword this

SCHEMA di una function -- può essere passata come parametro o ritornata come output
function( lista argomenti ) { internal | external }
[constant]
[payable]
returns ( return tipo )

pragma solidity 0.4.16;

contract Test {
int public aa;

string private commento;
function a() public external {}

function b() public internal {}

function c() private {}

}

SECURITY - VIEW - PURE

Per evitare che gli hacker possano usare in modo inappropriato gli Smart Contract e prelevare gli ether connessi ai wallet come già avvenuto in alcuni casi si consglia di usare quelle che vengono definite le best practice per la scrittura dei programmi.

Vediamo alcune indicazioni che vengono consigliate:
- codificare secondo uno standard per il naming e style
- fare moltissimi test e fare test come se si fosse un hacher
- settare i valore nello storage
- inserire l'emissione degli eventi nelle function
- creare nueve istanza dei contracts
- usare low level calls
- usare selfdestruct
- allo scopo di prevenire un uso improprio vengono fornite delle keywords per definire in modo preciso e puntuale cosa si intende effettuare, queste sono VIEW PURE inoltre PUBBLIC PRIVATE INTERNAL EXTERNAL

Ora vediamo VIEW e PURE cosa sono e come usarle

VIEW
Indica alla function che è permessa la READ dello STORAGE ma non è consentita la CHANGE OF STATE cioè non ci permette di modificare una variabile che risiede nello storage

Vediamo un esempio dove andiamo a modificare nella function il contenuto di una variabile definita nello storage
contract testSecurity {

uint risultato;
function getData() public returns (uint) {
var risultato = storagevar + 5;
return risultato;
}
}

per evitare questo uso non corretto possiamo scrivere il nostro contract nel modo seguente
contract testSecurity {
function getData() view public returns (uint) {
return 5
}
}
PURE
Pure è ancora più restrittiva perchè non permette ne la READ dello STORAGE ne modificare dati nello STORAGE (no state change) e vediamo un esempio del caso precedente
contract testSecurity {
function getData() pure public returns (uint) {
return 5
}
}

Si consiglia di dare alle function nomi appropriati a quella che è la vera function ad esempio non dare il nome di riceviCostante se poi si riceve una variabile.

Si fa presente inoltre che ora il COMPILATORE ritorna un errore che segnala che non si sta scrivendo il codice non seguendo la best practice.

ETHER

The Ethereum cryptocurrency composed by different unit of measure and can be converted. The unit are wei(default measurement unit) ether finney szabo ecc.. go to ethereum project for view eth-converter

TIME

NOW di type uint256
• Ritorna il tempo in secondi a partire dal 1970
• Poi è possibile convertire da secondi in minuti , ore, giorni, settimane ed anni

BLOCK

La funzione BLOCK ci ritorna informazioni sul blocco corrente della blockchain su cui è stato inserito lo smart contract.
Le informazioni che possiamo ottenere sono ad esempio number, coinbase, timestamp, difficulty, gaslimit

int number = block.number
Mentre la funzione block.blockhash(uint blkNum) returns (bytes32) ci ritorna i codici hashes degli ultimi 256 blocchi. tx - Transaction
tx.gasprice -> gas price for the transaction if payable
tx.origin -> do not use - its preferible use msg.sender

FUNCTION TX

tx - Transaction
tx.gasprice ci dà il gas price per la transazione se payable
tx.origin -- consigliato -- do not use - è preferibile usare msg.sender per conoscere chi ha iniziato la transazione

FUNCTION MSG

Msg
La funzione msg ci fornisce informazioni del messaggio
msg.data - dati del messaggio in bytes
msg.sender - l'address del mittente (0x0...)
msg.sig - primi 4 byte dei dati del msg
msg.value - se c'è opzione payable indica quanti wei vengono trasferiti

EXCEPTION

Throw() do not use DEPRECATED recommended Use require() or revert()
Revert()
• Aborts the transaction execution
• All state changes are reverted
• No ethers are sent out
• Ethers received in transaction returned
• Refunds the unused gas
• Transaction is recorded on the chain; nonce is valid & recorded

Assert(condition)
• throws if condition is not true - Lancia una eccezione se condizione FALSE

Require(condition)
• Come assert lancia una exception ma se la condizione TRUE
pragma solidity 0.4.22;

contract Test {
uint8 public partecipanti;
function a() public view returns (bool) { //ASSERT
assert(partecipanti > 50);
return true;
}

function b() public view { //REVERT
if (partecipanti > 70 )
revert("Troppi partecipanti per il momento il viaggio è sospeso");
}

function c() public view { //REQUIRE
require(
partecipanti < 30 || partecipanti > 40 ,
"Il viaggio viene confermato solo con numero partecipanti prestabilito."
);
}
}

CONSTANT

Per le variabili solo int e string. Mentre per le function indica la promessa di non modificare lo stato del contract.
pragma solidity 0.4.22;

contract Test {
uint8 constant partecipanti = 50;
string constant testo = 'Hello';
uint8 np;
function b(uint8 numero) public constant {
np = numero ;
}
}

FALLBACK FUNCTION

• An un-named function in the contract
• Invoked without the data
• Restrictions:
• No arguments • Cannot return anything • Maximum gas spend = 2300 gas
pragma solidity ^0.6.0;

contract Test {

fallback() external payable {
......
}
}

MODIFIERS

Funzione speciale che si usa per modificare il contesto di una funzione. Può avere o no arguments
Variabili interne al modifier non possono essere utilizzate in altre funzioni
Si possono applicare + modifier ad una funzione:
- ordine importante.
Hai Modifiers si può applicare la Inheritance e poi possono essere modificati.
modifier onlyOwner {
//onlyOwner la funzione viene esguita solo se la call proviene dall'owner
require(msg.sender == owner);
_; //body function
}

LOG

Ad ogni transazione che viene eseguita log update ed inseriti eventi definiti nel contract. Log può essere visionato per checks e ricerche da Javascript

EVENTS

Events
//Dichiarazione di un Event
event PrimoEvento(address utente, bytes id, uint256 time);
//Emit an event
emit PrimoEvento(sender, _id, time_evento);

event NewEvent(address indexed who, string name, uint importo); max 3 args

function a() payable b {
if (msg.sender == owner) {
NewEvent(msg.sender, b, msg.value);
}
}

SMART CONTRACT

Ciclo di vita di uno Smart Contract
Quando il contract cìviene compilato viene creata una ABI DEFINATION che inserita nella blockchain può essere poi invocata per l'esecuzione
Negli smart contract si può inserire una opzione, la self-destruct, che permette una volta che il contract è stato eseguito di eliminarlo dalla blockcgain.

SELF DESTRUCT

Negli smart contract si può inserire una opzione, la self-destruct, che permette una volta che il contract è stato eseguito di eliminarlo dalla blockcgain ed i restanti ether assegnati al contract verranno inviati al target(address) designato.
Problema: il contract non è più eseguibile ma se qualcuno tramite transaction send ether questi verranno persi. Per ovviare a questo problema o si elimina ogni riferimento del contract o si può non inserire la clausola self-destruct ma modificare le funcion in internal ad esempio in modo che se qualcuno prova ad eseguire la funcion questa genererà un REVERT e l'ammontare della transaction verrà riassegnato al mittente.
<<<<<<< HEAD modifier onlyOwner {
if (msg.sender != owner) {
throws
} else {
_;
}
}

======= >>>>>>> 9c9fa20bfd1d5750ed4e64427483953b98fdf9f9 function killContract() onlyOwner {
Suicide(myconto) //the contract send balance to this address
}

<<<<<<< HEAD

DESIGN PATTERN

Ogni Smart Contract ha il seguente ciclo di vita con le 2 principali fasi che sono il deploy e poi l'invoking dello stesso ma capita che ad un certo punto il contract abbia esaurito la sua efficacia per cui se invocato non vada in esecuzione per cui si consiglia di usare la clausola self-destruct per la cui trattazione si rimanda al punto precedente.

Vediamo ora dei Design Pattern che possono essere utili in base alla tipologia di contract da realizzare.

FATTORY PATTERN

Con il Fattory Pattern invece di creare tanti contratti uguali si crea un contratto standard e poi si fanno tante istanze una per ogni nuovo contract che poi può essere modificato ed esssere così diverso dagli altri.
Conseguenze di questo design pattern sono l'utilizzo dello storage nel factory e un uso maggiore di gas.
I vantaggi sono che si nasconde la complissità e incapsula business rule inoltre si possono gestire i contracts in una collection e si possono inserire delle modifiche e nuovi insert.
Descriviamo un esempio di una dapp per gestire diverse tipologie di clienti dove si definiscono diverse tipologie di clienti con le proprie regole ed autorizzazioni. In base ad un parametro automaticamente quando si inserisce il cliente questo viene assegnato alla classe di appartenenza.
In futuro le change verranno fatte nel fattory contract senza dover modificare tutti i contracts.

NAME REGISTRY

Se nella Dapp ho molti contrats devo conoscere il contract hash di ciascuno di esso e delle istanza associate così per evitare questo si possono creare degli indipendet registry address creati con nome ed indirizzo del contracts si tratta di una mappa dove indicando il nome del contract ricevo indirizzo dello stesso e posso poi interagire con esso.
I vantaggi sono che possiamo avere una gestione semplice, l'app usa nome contracts invece di indirizzo inoltre in caso di un contract sostituito con una nuova versione si modifica solo l'indirizzo fisico nella name registry mentre nella dapp non si deve modificare nulla.
Qui rappresentiamo come costruire un semplice name registry
struct ContractData {
address owner;
address instance;
uint18 version;
}

mapping(bytes32 => contractData) nameRegistro;
=======

>>>>>>> 9c9fa20bfd1d5750ed4e64427483953b98fdf9f9