Dapp — Tutorial Integrazione del protocollo Aave

Deabit Bloggers
Deabit
Published in
10 min readMay 8, 2020

--

Dopo aver fatto un’introduzione al concetto di Dapp, mettiamo un po’ le mani in pasta e ci avviciniamo un po’ di più a quelle che sono le logiche dietro una Dapp.

In questo articolo faremo un breve tutorial sull’implementazione di una Dapp con l’integrazione del protocollo Aave per accedere ad un nuovo paradigma che la blockchain porta con se, ovvero quello della Defi (Decentralized Finance).

Ma che cos’è Aave?

Aave è una società che fornisce una piattaforma decentralizzata, blockchain-based, con vari servizi con un modello “Pooled Lending”, tra questi, spicca il servizio di Flash Loan che fornisce dei prestiti in crypto senza la necessità di mettere a disposizione un collaterale a copertura del credito.

Ma arriviamo al sodo, let’s go to the coding!

Fase Architetturale

Come prima fase impostiamo l’architettura della Dapp, utilizzeremo la libreria React che fornisce un’immediata integrazione con il mondo della blockchain attraverso il modulo web3.

npx create-react-app deabitloans

Attraverso questa semplice istruzione da shell viene istanziato il nostro progetto react con all’interno la struttura della Dapp.

A fine processo vi troverete una cartella chiamata deabitloans, apritela con il vostro IDE preferito e vi ritroverete di fronte a questa struttura dati:

A questo punto dobbiamo eseguire un passaggio fondamentale, ovvero l’installazione del modulo web3 recandoci con la shell all’interno della cartella del progetto ed eseguendo il seguente comando:

npm install web3

Dopo aver eseguito questo passaggio, restiamo nella cartella del progetto e facciamo un piccolo check di verifica della parte architetturale vedendo se riusciamo ad eseguire il progetto react in localhost:

npm start

Se tutto è andato a buon fine, vi si dovrebbe aprire il browser con il puntamento verso il webserver in locale appena istanziato:

Le Dapp sono definite decentralizzate proprio perchè non hanno un punto centrale di raccolta dati e ogni utente ha pieno potere sui propri dati, tuttavia la blockchain di per se non “esce” su internet e per interagire con essa abbiamo bisogno di un provider, ovvero di un nodo, in questo caso, della blockchain di ethereum.

Ecco che ci viene in aiuto metamask, un estensione del browser che racchiude al suo interno un nodo light e che ci fa da interfaccia verso la blockchain.

Potete scaricare metamask al seguente indirizzo:https://metamask.io/download.html

Ad installazione eseguita creiamo il nostro wallet in testnet (Ropsten) ed utilizziamo un faucet per inviarci degli eth di test: https://faucet.ropsten.be/

Testing Metamask

A questo punto abbiamo tutto il necessario per iniziare a sviluppare la nostra dapp.

Prima però testiamo quella che è una parte fondamentale per il funzionamento della dapp: la connessione con il provider.

Cominciamo con il creare una nuova cartella all’interno del progetto:

cd src/mkdir componentscd components

Qui creeremo i nostri component che vedremo successivamente, per ora creiamo solo il file “connectMetamask.js”.

Adesso dobbiamo controllare se nel browser è presente metamask.

Lo facciamo attraverso l’implementazione di un custom hook da esportare nel file App.js.

import {useState} from 'react'

import Web3 from "web3";



export const ConnectMetamask = () => {

const [account,setAccoount] = useState()

const web3 = new Web3(window.web3.currentProvider);



let AccString;

const autorizeApp = async () =>{

if (window.ethereum) {

window.ethereum.autoRefreshOnNetworkChange = false;

window.web3 = new Web3(window.ethereum);

try {

await window.ethereum.enable();

let AccObj = await web3.eth.getAccounts();

AccString = AccObj[0];

setAccount(AccString)



} catch (error) {console.log(`errore con il caricamento dell'istanza web3: ${error}`)}

}

// Legacy dapp browsers...

else if
(window.web3) {window.web3 = new Web3(web3.currentProvider);}

// Non-dapp browsers...

else
{console.log('provider non trovato,scarica metamsk!');}

return AccString;

}



return [account,setAccount,autorizeApp];

};



export default ConnectMetamask;

Adesso dobbiamo riportare il custom hook nel componente padre e richiamare la funzione autorizeApp da un pulsante

const [account,setAccount,autorizeApp] = ConnectMetamask();<button onClick={autorizeApp}>Connetti a Metamask<button/>

Cliccando sul pulsante vi troverete di fronte ad una finestra del browser come questa:

Clicchiamo sul pulsante Connetti cosi da avere pieno accesso alla blockchain di ethereum.

Fase di sviluppo

Finita la fase architetturale e di configurazione della connessione alla blockchain arriva la parte clou: lo sviluppo!

Aave è presente sulla blockchain con una serie di smart contract che forniscono una vasta gamma di metodi.

In questo tutorial ci concentreremo solo su quelli esposti dallo smart contract LendingPool per integrare nella nostra dapp i metodi necessari per poter richiedere e gestire un prestito standard con collaterale a copertura del credito richiesto.

Procediamo con l’istanziare lo smart contract denominato LendingPool, lo facciamo attraverso lo stesso approccio utilizzato pocanzi, ovvero creando un custom hook da riportare in App.js

Creiamo un nuovo file nella cartella components e lo chiamiamo “istanceLendingPoolContract.js”

Nota: è importante scaricare l’interfaccia ABI degli smart contract per istanziarli, potete scaricarli qui: https://github.com/aave/aave-protocol/tree/master/abi

Per rendere il tutto più dinamico utilizziamo una interfaccia esposta da Aave: LendingPoolAddressProvider, che ci permette di recapitare l’indirizzo dell’ultima versione disponibile dello smart contract che vogliamo richiamare:

import lendAddrProvider from "../lendAddressProvider";

import lendingPool from "../lendingPool";

import Web3 from "web3";

import {useState} from 'react'

let web3 = new Web3(window.web3.currentProvider);


export const IstanceLendingPoll = ()=>{

const [LendingPoolContract, setLendingPoolContract] = useState();

const getLendingPool = async () =>{


const addrProvider = "0x1c8756FD2B28e9426CDBDcC7E3c4d64fa9A54728"; //ropsten address...
`const ProviderContract = new web3.eth.Contract(lendAddrProvider,addrProvider);

const addrLendingPool = await ProviderContract.methods.getLendingPool().call().catch((e)=>console.log(`error ${e}`));

setLendingPoolContract( new web3.eth.Contract(lendingPool,addrLendingPool));

}

return [LendingPoolContract,setLendingPoolContract,getLendingPool]

}


export default IstanceLendingPoll;

Riportiamo il custom hook nel componente padre:

const [LendingPoolContract, setLendingPoolContract,getLendingPool] =IstanceLendingPoll();

Per far si che l’istanza dello smart contract sia presente fin da subito utilizziamo una nuova feature introdotta da react, ovvero l’uso del hook “useEffect” che avvia la sua esecuzione fin dai primi istanti del montaggio del componente

useEffect(() =>{

getLendingPool();


},[])

Per ora al suo interno richiamiamo solo la funzione esposta dal nostro custom hook che ci permette di avere fin da subito l’istanza del nostro smart contract.

Test

Adesso verifichiamo che il nostro smart contract sia istanziato correttamente:

creiamo una funzione asincrona all’interno di App.js e facciamo il log dei metodi esposti dallo smart contract:

const verificaIstanza = async () => {let metodi = await LendingPoolContract.methods;console.log(metodi);

}

Richiamo questa funzione in un pulsante:

<button onClick={verificaIstanza}>Verifica<button/>

Salviamo, e verifichiamo cliccando sul pulsante tendo aperta la sezione per sviluppatori del browser

Se avete fatto tutto bene, nella sezione per sviluppatori del browser vedrete questo:

A test eseguito, proseguiamo con l’implementazione.

Deposito

Nella nostra dapp vogliamo poter depositare un collaterale nella pool di aave per far si che alla richiesta di un prestito, esso vada a fare da garanzia in caso di mancato pagamento. A transazione confermata riceveremo il corrispettivo del deposito in “aToken” offerti gentilmente da aave 😊

Useremo il metodo deposit per eseguire questa operazione:

creiamo una nuova funzione asincrona in App.js chiamata depositOnLendingPool:

const depositOnLendingPool = async (ImportoDeposito) =>{let importoDeposit = web3.utils.toWei(ImportoDeposito,"ether");let refcode = “0”;let addrMockETH = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";await LendingPoolContract.methods.deposit(addrMockETH, importoDeposit, refcode)

.send({from:AccountLogged,value: importoDeposit }).catch((e)=>console.log(e));
}

In questo caso depositiamo ether ed utilizziamo con indirizzo dello smart contract uno fornito da aave se volessimo depositare altre crypto dovremmo richiedere lo specifico indirizzo, ne trovate alcuni qui .

I parametri da passare sono: indirizzo dello smart contract (addrMockETH),importo da depositare (importoDeposit) e referal code, che può avere un valore uguale a 0 (refcode)

Richiamiamo la funzione attraverso un pulsante e inseriamo l’importo che vogliamo depositare attraverso un campo d’input

Per catturare il valore inserito nel campo d’input abbiamo bisogno d’implementare un evento, che prenda il valore e lo setti in uno stato.

Const [ImportoDeposito,setImportoDepostio] = useState()const valueInputDeposit =(event) =>{

event.target.value === null?
setImportoDeposito("0.0"):setImportoDeposito(event.target.value)

}

Test

Okay proviamo se tutto funziona:

Verificate che gli ethereum di test vi siano arrivati:

Inseriamo nel campo d’input 0.1 e clicchiamo sul pulsante Invia

Se avete fatto tutto bene, vi uscira la solita finestra di metamask:

Clicchiamo sul pulsante conferma per effettuare il deposito e attendiamo la conferma della transazione.

Se tutto è andato a buon fine avremo il nostro 0.1 in aETH nel nostro wallet

Adesso siamo pronti per richiedere un prestito!

Prestito

Dopo aver depositato i nostri ether siamo pronti per richiedere un prestito.

Utilizziamo un metodo dello smart contract LendingPool chiamato borrow.

Richiederemo un prestito in DAI, ormai nota stable coin nell’ecosistema ethereum.

Come abbiamo fatto in precedenza creiamo una nuova funzione in App.js chiamata makeBorrowOnLendingPool.

const makeBorrowOnLendingPool = async (importoPrestito) =>{

const addrDAI = "0xf80A32A835F79D7787E8a8ee5721D0fEaFd78108"; //ropsten address...

let
tassoInteresse = 2 // 2 = tasso variabile || 1 = tasso fisso

let
refcode = “0”;

let amountPrestito = web3.utils.toWei(importoPrestito,"ether")

await LendingPoolContract.methods.borrow(addrDAI,
amountPrestito,
tassoInteresse,
refcode)
.send({from:AccountLogged}).catch((e)=>console.log(e))



}

I parametri da passare sono:

· Indirizzo dello smart contract DAI

· Importo del prestito richiesto

· Tasso d’interesse

· Referal code

Anche qui richiamiamo la funzione attraverso un pulsante e inseriamo l’importo che vogliamo depositare attraverso un campo d’input

<button onClick={ makeBorrowOnLendingPool }>Invia<button/><input onChange={valueInputBorrow}/>

Per catturare il valore inserito nel campo d’input abbiamo bisogno d’implementare un evento, che prenda il valore e lo setti in uno stato.

Const [ImportoPrestito,setImportoPrestito] = useState()

const valueInputBorrow =(event) =>{



event.target.value === null? setImportoDeposito("0.0"): setImportoDeposito(event.target.value)

}

Test

Okay proviamo se tutto funziona:

Inseriamo nel campo d’input 0.05, che sara l’importo del prestito in DAI che riceveremo e clicchiamo sul pulsante Invia

Se avete fatto tutto bene, vi uscirà la solita finestra di metamask:

Nota: in questo caso i valori sono a 0 in quanto non c’e bisogno d’inviare nulla per la richiesta di prestito e il collaterale è gia stato depositato in precedenza

Clicchiamo sul pulsante conferma per effettuare la richiesta di prestito e attendiamo la conferma della transazione.

Se tutto è andato a buon fine avremo il nostro 0.05 in DAI nel nostro wallet

That’s It!

Ripaghiamo il Prestito

Dal dizionario Treccani possiamo evincere:

prèstito s. m. [dal lat. praestĭtum, propr. part. pass. neutro di praestare: v. prestare]. — 1. L’atto del prestare, il fatto di dare o ricevere qualche cosa (denaro, un bene, un oggetto) con l’impegno di restituirla entro un periodo di tempo determinato o non determinato

pertanto si può dedurre che anche nel fantastico mondo della blockchain, i prestiti vanno restituiti.

Il protocollo aave ci viene in contro esponendo il metodo repay, con il quale noi possiamo restituire parte o tutto l’ammontare del prestito chiesto precedentemente.

Prima di creare la nostra consueta funzione, dobbiamo creare un nuovo custom hook, in cui creiamo l’istanza del contratto del token DAI, in quanto per restituire il nostro prestito abbiamo la necessita di chiamare il metodo approve di DAI e solo successivamente possiamo restituire l’importo.

Creiamo un nuovo file nella cartella component chiamato “istanceDaiContract.js”

import {useState} from "react";

import lendAddrProvider from "../lendAddressProvider";

import DaiToken from "../DaiABI";

import Web3 from "web3";

let web3 = new Web3(window.web3.currentProvider);



export const IstanceDaiContract = () =>{
const [DaiContract,setDaiContract] = useState();



const getDaiContract = async () =>{
const addrDAI = "0xf80A32A835F79D7787E8a8ee5721D0fEaFd78108"; //ropsten address...const addrProvider = "0x1c8756FD2B28e9426CDBDcC7E3c4d64fa9A54728"; //ropsten address...const ProviderContract = new web3.eth.Contract(lendAddrProvider,addrProvider);const addrLendingPoolCore = await ProviderContract.methods.getLendingPoolCore().call().catch((e)=>console.log(`error ${e}`));

setDaiContract(new web3.eth.Contract(DaiToken, addrDAI))

}

return [DaiContract,setDaiContract,getDaiContract]

}



export default IstanceDaiContract;

Nota: per istanziare lo smart contract DAI avete bisogno del ABI, che è quello di un erc20 comune, potete scricarlo qui

Esportiamo come di consueto il custom hook in App.js

const [DaiContract,setDaiContract,getDaiContract] = IstanceDaiContract();

A questo punto abbiamo l’istanza ma tra i parametri del metodo approva, va inserito l’indirizzo dello smart contract da autorizzare, nel nostro caso si tratta del’indirizzo del contratto LendingPoolCore.

Creiamo un nuovo custom hook chiamato “istanceLendingPoolCoreContract.js”

import {useState} from "react";

import lendAddrProvider from "../lendAddressProvider";

import Web3 from "web3";

let web3 = new Web3(window.web3.currentProvider);





export const IstanceLendingPoolCoreContract = () =>{
const [LendingPoolCoreContract,setLendingPoolCoreContract] = useState();const getLendingPoolCoreContract = async () =>{const addrProvider = "0x1c8756FD2B28e9426CDBDcC7E3c4d64fa9A54728"; //ropsten address...

const
ProviderContract = new web3.eth.Contract(lendAddrProvider,addrProvider);
const addrLendingPoolCore = await ProviderContract.methods.getLendingPoolCore().call().catch((e)=>console.log(`error ${e}`));

setLendingPoolCoreContract(addrLendingPoolCore);

}
return [LendingPoolCoreContract,setLendingPoolCoreContract,getLendingPoolCoreContract]

}



export default IstanceLendingPoolCoreContract;

Riportiamo il custom hook in App.js

const [LendingPoolCoreContract,setLendingPoolCoreContract,getLendingPoolCoreContract] = IstanceLendingPoolCoreContract();

Adesso aggiungiamo la funzione dell’ istanza DaiContract e quella dell’istanza LendingPoolCore nel hook useEffect cosi da averle pronte fin da subito:

useEffect(() =>{getLendingPool();getDaiContract();getLendingPoolCoreContract();},[])

A questo punto abbiamo tutto il necessario per implementare la nostra funzione di restituzione del prestito, ma prima implementiamo quella d’approvazione..

Creiamo una nuova funzione chiamata makeApprove:

const makeApprove = async (importoDaApprovare) =>{let amountDaApprovare = web3.utils.toWei(importoDaApprovare,"ether");await DaiContract.methods.approve(LendingPoolCoreContract,amountDaApprovare)

.send({from:AccountLogged}).catch((e)=>console.log(e))
}

Richiamiamola in un pulsante:

<button onClick={ makeApprove }>Invia richieta di approvazione<button/>

Per recepire l’importo creiamo un evento

const valueInputRepay =(event) =>{



event.target.value === null? setImportoRepay("0.0"): setImportoRepay(event.target.value)

}

e richiamiamolo in un campo d’input

<input onChange={valueInputRepay}/>

Poi creiamo un’altra funzione chiamata setRepayOnLendingPool

const setRepayOnLendingPool = async (importo) =>{let importoDaRestituire = web3.utils.toWei(importo,"ether");await LendingPoolContract.methods.repay(addrDAI,importoDaRestituire,AccountLogged)

.send({from:AccountLogged}).catch((e)=>console.log(e))

}

e richiamiamola in un altro pulsante che provvederà ad restituire l’importo inserito.

Test

Okay proviamo se tutto funziona:

Inseriamo nel campo d’input 0.03, che sara l’importo del prestito in DAI che restituiremo e clicchiamo sul pulsante Invia richiesta d’approvazione

Vi ritroverete davanti ad una finestra di metamask un po’ diversa dal solito..

Clicchiamo sul pulsante conferma per effettuare la richiesta di approvazione e attendiamo la conferma della transazione.

A transazione confermata clicchiamo sul tasto Invia:

E successivamente conferma su metamask.

Se tutto è andato a buon fine vedremo che ci restano 0.02 DAI nel nostro wallet:

That’s It!

Conclusione

In questo tutorial abbiamo visto molte cose ma chiaramente non bastano per mettere in produzione la vostra dapp, in quanto ci sono molti altri accorgimenti da prendere per garantire totale sicurezza dei fondi che la vostra community depositerà o richiederà attraverso la vostra dapp.

Ma non temete, è il primo di una lunga serie.

Potete visionare il codice del tutorial qui: https://github.com/DeabitTech/DeaBitLoans.git

--

--