Nella seconda metà del mese di febbraio ho iniziato a studiare solidity. In questo ambito ho iniziato a studiare semplici codici, a scrivere qualche piccolo script e a modificare i codici di esempio forniti dalla libreria stessa. I programmi sono:
- note.sol
- atleti.sol
- votazione.sol (partito da esempi della libreria solidity)
- asta.sol (partito da esempi della libreria solidity)
- OffertaScatolaChiusa.sol (partito da esempi della libreria solidity)
- vendita: singlePuchase e Purchese (partito da esempi della libreria solidity)
Semplice programma che permette di salvare, modificare e stampare delle note. Questo programma ha l'idea di essere una base per una checklist di attività da fare o sviluppi simili.
Permette la registrazione di atleti con il loro punteggio, modificare il punteggio e ritornare la classifica degli atleti.
Viene creato il contratto "Votazione" per gestire un sistema di votazione nel quale:
- constructor: il creatore, colui che chiama il contratto, crea una lista delle persone candidabili per la votazione;
- dareDirittoVoto: il creatore può dare il diritto di voto agli indirizzi della rete;
- deleteDirittoVoto: il creatore può rimuovere il diritto di voto agli indirizza a cui è stato assegnato;
- delega: gli utenti possono delegare il voto;
- deleteDelega: cancellare la delaga;
- voto: permette di votare;
- deleteVoto: viene eliminato il voto assegnato;
- changeDelega: permette di cambiare la delega fatta;
- changeVoto: permette di cambiare il voto fatto;
- classificaTop5: permette di sapere i primi 5 classificati;
- vincitore: il creato può definire il vincitore. Al momento non chiude la votazione ma è uno degli sviluppi più plausibili.
- andiamo a:
- definire 5 candidati (sono stati effettuati test anche con piu e meno di 5 candidati, questi test non sono stati approfonditi): ["0x1000000000000000000000000000000000000000000000000000000000000000", "0x2000000000000000000000000000000000000000000000000000000000000000", "0x3000000000000000000000000000000000000000000000000000000000000000", "0x4000000000000000000000000000000000000000000000000000000000000000", "0x5000000000000000000000000000000000000000000000000000000000000000"]
- dare diritto di voto a 5 indirizzi (test sempre con numeri minori):
0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 (creatore -> errore perchè inizializzato in partenza)
0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2
0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db
0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB
0x617F2E2fD72FD9D5503197092aC168c91465E7f2
- si delega il primo al secondo
- il secondo al primo (andrà in errore)
- si delega il secondo al terzo
- si vota con il terzo il primo candito
- con il quarto indirizzo si delega il primo
- si elimina la delega del primo votante
- il primo indirizzo vota il secondo candidato
- si chiede la classifica (primo 2 voti, secondo 2 voti)
- si chiama il vincitore ci sarà un pareggio (andrà in errore)
- cambio la delega del secondo dal terzo al primo
- cambio voto del primo indirizzo voterà il terzo candidato
- si elimina diritto di voto del secondo
- rimuovere diretto di voto al quinto indirizzo e provare a farlo votare (errore)
- riassegnare diritto di voto al quinto indirizzo e farlo votare il secondo candidato
- classifica finale dei primi 5 candidati: primo 1 voti, secondo 1 voto e terzo 2 voto
- chiamare il vincitore che sarà il terzo candidato Non sono stati effettuati ulteriori test
Il programma asta si prefigge l'obiettivo di creare una semplice asta. Con il seguente algoritmo un indirizzo può creare un asta, gli altri indirizzo possono fare offerte maggiori. Per far questo creiamo:
- Costruttore:
- il beneficario
- l'offerta minama
- il tempo di scadenza di un asta
- incremento minimo
- funzione offerta(uint amount) return tempo rimante: in questa funzione si controlla inanzitutto se il tempo per effettuare offerte è scaduto, in tal caso si andrà in errore (revert nome errore)* si controlla che tu non sia il migliorOffertent si controlla se l'offerta (msg.value) non è sufficiente per superare la precedente offerta e in tal caso si manda in errore si rimandano al vecchio offerente i suoi soldi (chiamando funzione withdraw) si cambiano i dati del miglior offerente si manda un messaggio con la nuova offerta (chiamato con emit)
- funzione fineAsta(): si richiede che il tempo sia scaduto; si chiama evento fine asta in cui si riporta il portafoglio del vincitore e l'amount(chiamato con emit) si mandano i soldi al beneficario
*NOTA BENE: l'intenzione iniziale era quella di far chiamare la funzione fineAsta alla prima offerta dopo che il tempo scadeva ma l'esecuzione in concomitanza della funzione fineAsta e dell'errore non è stata possibile. Togliendo i commenti dalle righe commentate nel codice la prima volta in cui si chiama offerta() dopo il termine tempo verrà chiameta fineAsta() e solo dalla seconda volta la funzione andrà in errore. Chiaramente a livello logico, questo problema verrà risolto a livello applicativo: quando scadrà il tempo l'applicazione chiamerà fineAsta()
- Si crea un contratto in cui il beneficario è 0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB, l'offerta è 10, la durata è 180 secondi, incremento minimo è 0.1:
0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB, 10, 180, 2 - Si utilizzeranno i seguenti portafoglio per la fase di test:
0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 (creatore - primo indirizzo)
0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 (secondo indirizzo)
0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db (terzo indirizzo)
- con il primo portafoglio si va a fare un'offerta pari a 8 (errore sotto soglia);
- con il primo portafoglio si va a fare un'offerta pari a 15;
- con il primo portafoglio si va a fare un'offerta pari a 17 (errore perchè si è già il miglior offerente);
- con il secondo portafoglio si va ad offrire 110 (errore più dei soldi a disposizione);
- con il secondo si andrà ad offrire 12, errore perchè minore della miglior offerta;
- con il secondo si offrirà 16, errore perchè non si incrementa almeno di 2;
- con il secondo si offrirà 17;
- con il terzo si offrirà 20;
- nell'ultimo minuto con il primo si offrirà 30 -> incremeterà il tempo di offerta di 1 minuto
- aspettiamo alcuni secondi e secondo si offrirà 35;
- aspettiamo circa 30 secondi e il terzo offrirà 37;
- dopo almeno 1 minuto, il primo offrirà 40 -> errore asta finità e i soldi verranno mandati al beneficario. Non sono stati effettuati ulteriori test
Variabili:
- address[] partecipanti
- mapping offerente(address => offerte)
- struttura offerte{ bytes32 cifraOfferta da cifrare uint soldiInviati }
- address beneficiario
- uint offerenteMinima
- uint scadenzaAsta
- address creatore
Costruttore:
- tempo scadenza asta
- beneficiario
- offerta minima
- creatore
Offerta(uint cifra):
- cifra > offerta minima (required)
- cifra < soldi inviati (msg.value)
- now < tempo scadenza asta
- se sender non è presente trai partecipanti viene aggiunto indizzo ai partecipanti altrimenti viene chiamata la funzione annullaOfferta
- salvare il valore dei soldi inviati = msg.value e dei soldi realmente offerti (cifra) DA CIFRARE NOTA BENE: il sistema di cifratura va rivisto perchè è facilmente recuperabile la massima offerta
annullaOfferta():
- required sender in partecipanti
- soldi inviati > 0
- invio soldi inviati;
- soldi offerti = bytes32(0);
- soldi inviati = 0
vincitore() return(addr, amount):
- required: solo creatore può chiamare la funzione tempo dell'asta deve essere scaduto
- si notifica chiusura asta
- required: array partecipanti non sia nullo
- ciclo for sui partecipanti. si cerca l'offerta massima (utilizzare variabile di supporto uint offMass). Per fare questo bisogna decifrare il valore si salva la posizione dell'indirizzo con offerta più alta (utilizzare var di supporto uint poss)
- si verifica che l'offerta massima non sia 0 => errore.
- si inviano i soldi al beneficiario
- si inviano i soldi in più al offerente
- nell'array partecipanti si sostituisce l'offerente in posizione 0 con quello con offerta massima (e viceversa) -> NOTA: nella funzione ritorno soldi partiamo da 1
- si chiama la funzione ritornoSoldi()
- return valori
ritornoSoldi():
- ciclo for sugli indirizzi partendo con i=1 (NON 0) se soldi>0: si rinvia i soldi ricevuti
- andiamo a utilizzare 4 indirizzi:
0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 (creatore -> errore perchè inizializzato in partenza)
0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2
0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db
0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB - Si crea un contratto in cui il beneficario è 0x617F2E2fD72FD9D5503197092aC168c91465E7f2, l'offerta è 10, la durata è 180 secondi:
0x617F2E2fD72FD9D5503197092aC168c91465E7f2, 10, 180
- il primo fa un offerta di 10 mandando 20
- il secondo prova a offire 8 (errore)
- il secondo offre 15 e manda 30
- il secondo elimina l'offerta fatta
- si chiama vincitore (non sarà finita l'asta -> errore)
- il terzo prova a offri 20 e mandare 15 (errore)
- il terzo offre 20 e manda 30
- il terzo offre 25 e manda 30 (cambia offerta)
- finisce asta, il quarto prova a fare un offerta (errore)
- il quarto prova a chiamare il vincitore (errore perchè non proprietario) Non sono stati effettuati ulteriori test
Il seguente sistema garantisce che la vendità di un prodotto avvenga in quanto è nell'interesse sia del venditore che dell'acquirente. Per far questo l'entrambi mettono 2 volte il prezzo del prodotto e una volta conclusa l'operazione il venditore ricevera 3/2 e l'acquirente 1/2.
Per rendere chiaro lo sviluppo è stato deciso di creare 2 classi:
- singlePuchase: permetta la gestione di una vendita basato su una macchina a stati diniti
- Purchese: permette la gestione di molteplici vendite. I prodotti saranno istanza del contratto singlePuchase
In dettaglio il funzionamento del contratto singlePuchase:
- si basa su una macchina a stati in cui sono presenti 4 stati: MessaVendita (iniziale), AccettaCliente, ProdottoInviato, VenditaConclusa (finale)
- sono previsti un venditore, un acquirente
- sono presenti 4 funzioni per riportare il valore delle variabile, al momento non utilizzate, sostituibili quando utilizzate e di è da definirne l'utilità
- il costruttore imposta il nome del prodotto, il prezzo, lo stato iniziale della macchina, il venditore e richiede che il creatore abbia inviato 2 volte l'importo a cui vuole vendere il prodotto funzioni:
- modificaVendita(uint i) permette di modificare il prezzo di vendita
- acquista(): stato: MessaVendita -> AccettaCliente si definisce l'acquirente che invierà 2 volte il prezzo del prodotto
- annullaAcquisto(): stato: AccettaCliente -> MessaVendita sono il venditore o l'acquirente possono chiamare la funzione permette di annullare la richiesta di acquista del acquirente ma lascia il prodotto in vendita
- accettaAcquirente() stato: AccettaCliente -> ProdottoInviato con questa funzione il venditore accetta il cliente e garantisce l'invio del prodotto
- prodottoRicevuto() stato: ProdottoInviato -> (cambio in claim) VenditaConclusa l'acquirente può dichiarare l'arrivo del prodotto e così facendo chiama la funzione claim
- claim(): è di supporto a prodottoRicevuto() e serve a mandare i soldi (3/4 al venditore e 1/4 al acquirente)
- refound: sono 3 funzioni che permetto di ritornare i soldi inviati all'acquirente, al venditore o a entrambi;
- riepilogo(): ritorna lo stato della vendita con tutte le informazioni del caso: nome, importo, venditore, acquirente, stageì
In dettaglio il funzionamento del contratto singlePuchase:
- viene creato un array di singlePuchase;
- nel construttore si definisce il venditore si inizializza il primo valore dell'array di prodotti in vendita a null e questo non verrà mai utilizzato
- propostaVendita(string memory prod, uint i): permette di inizializzare una nuova vendita incaso la vendita sia già inizializzata permetti di cambiare il prezzo Da qui tutte le funzioni verificheranno l'esistenza del prodotto nell'array dei prodotti in vendita
- acquista(string memory prod): permette l'acquisto di un prodotto e in dettaglio chiama la funzione acquista() in singlePuchase
- annullaAcquisto(string memory prod): permette l'annullamento di un acquisto di un prodotto e in dettaglio chiama la funzione annullaAcquisto() in singlePuchase
- annullaVedita(string memory prod): può essere chiamata solo dal venditore o dal creatore e permette l'annulla della vendita chimando la funzione refoundAll() in singlePuchase
- accettaAcquirente(string memory prod): permette di accettare un acquirente attraverso la funzione accettaAcquirente() in singlePuchase
- prodottoRicevuto(string memory prod): la funzione chiama prodottoRicevuto() in singlePuchase concludendo la vendita e pertanto andando a notificare e eliminare il prodotto dall'array dei prodotti in vendita
- eliminaElArray(uint pos): permette di eliminare un elemento dell'array dei prodotti in vendita funzione a supporto di prodottoRicevuto
- riepilogo(string memory prod): riporta un riepilogo del prodotto in vendita quindi: posizione nell'array dei prodotti, nome, importo, venditore, acquirente, stage
- returnProdotti(): ritorna la lista dei prodotti in vendita;
- si crea una vendita: venditore 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, prodotto erba, importo 15 e si invia 15ETH: "erba", 15 => errore
- si crea una vendita: venditore 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, prodotto erba, importo 15 e si invia 40ETH: "erba", 15 => errore
- si crea una vendita: venditore 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, prodotto erba, importo 15 e si invia esattamente il doppio: "erba",15
- 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 prova ad acquista e invia 20 => errore
- 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 prova ad acquistare e invia 30
- riepilogo(): erba, 15, 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2, 1
- 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db prova ad acquistare e invia 30 => errore
- venditore annulla acquisto
- si modificaVendita: il prezzo cambia a 20 e invia 30 => errore
- si modificaVendita: il prezzo cambia a 20 e invia 40
- 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db prova ad acquistare e invia 40
- 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db (non venditore), prova ad accettare l'acquirente => errore
- venditore accetta offerta
- venditore prova a chiamare la funzione prodottoRicevuto() => errore
- riepilogo(): erba, 20, 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db, 3
- acquirente chiama prodotto ricevuto
- riepilogo(): erba, 20, 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db, 4
NOTA BENE: TODO: (finire i test e sistemare il codice)
- 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 crea il contratto
- 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 mette in vendita 2 prodotti: "arpa", 5 e invia 10 chitarra, 5 e invia 10
- 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db acquista arpa
- returnProdotti()
- riepilogo(arpa)
- 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 accetta la vendita per arpa
- 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db dichiara che arpa è arrivata
- riepilogo arpa => errore