Dapps
February 2, 2023

dApps | вызов функций по нажатию на кнопку

Привет сегодня поговорим о том, как мы можем добавить вызов функций смарт-контракта через сайт по кнопке и вывести результат на экран. Если вы не смотрели прошлую статью, то советую почитать.

Начну с того, что нам нужно добавить кнопку на нашем сайте. И параграф с нашим адресом

Теперь наша функция render из прошлого урока выглядит так:

render() {
    if(!this.state.selectedAccount) {
          return <> 
               <div>      
                 <ConnectWallet  connectWallet={this._connectWallet}
                  networkError={this.state.networkError} 
                  dismiss={this._dismissNetworkError}/>     
               </div >               
           </>     
    }    
    return(  <>    
          {this.state.balance &&      
          <p className={styles.balance}>
          balance: {ethers.utils.formatEther(this.state.balance)} 
          ETH</p>}   
                    
          <button onClick={this._checkAddress}> check address</button>
          
          <p>{this.state.checkAddress}</p>  
          
         </>  )    
}  }

Как видно я добавил метод при нажатии на кнопку

<button onClick={this._checkAddress}> check address</button>

При нажатии будет вызываться функция _checkAddress, которую мы напишем сейчас

_checkAddress = async() =>{   
   try{    
       const tx = await this.Lock.getAddress()    
       console.log(tx);    
       this.setState({     
            checkAddress: tx    
       })   
    }catch{    
       console.log("not an owner!");
          
       this.setState({     
          checkAddress: "not an owner!"   
       })  
        
     }         
   }

Как помним из прошлой статьи, то у нас в смарт контракте есть функция getAddress, которая возвращает адрес нашего кошелька. И так же есть модификатор который разрешает вызов этой функции только овнеру контракта.

Поэтому я использую систему try catch, которая будет отлавливать ошибку в случае, если вызвать функицию хочет не овнер контракта

Так же строчка

const tx = await this.Lock.getAddress()   

Это пример как мы должны вызывать функции из смарт контракта через frontend. await на нужна потому что вызов не моментальный, a this.Lock - это наш смарт контракт грубо говоря. Об этом подробнее было в прошлой статье.
В переменной tx будет значение которое вернет функция из нашего смарт контракта, в нашем случае адрес аккаунта который вызвал это функцию(то есть наш)

Далее я добавил в список глобальный переменных checkAddress
Теперь конструктор выглядит так:

constructor(props) {   
     super(props)      
     this.textInput = React.createRef();
      this.initialState = {    
          selectedAccount: null,        
          networkError: null,        
          balance: null,        
          checkAddress: null      
      }     
      this.state = this.initialState          
      }

И если отрабатывай try, то мы записываем tx в checkAddress и выводим через setState его на экран.

setState дает нам возможность обновлять глобальные переменные и перезаписывать в них аргументы, которые сразу же поменяются на нашем сайте

Ну а если catch то мы записываем, что вы не овнер контракта.

Все просто

Так же добавил в функцию initialize в setState, что при смене аккаунта у нас чистился checkAddress.

Функция initialize теперь выглядит так:

async _initialize(selectedAddress) {     
this._provider = new ethers.providers.Web3Provider(window.ethereum)        
      this.Lock = new ethers.Contract(    
          LockAddress.Lock,        
          LockArtifact.abi,        
          this._provider.getSigner(0)     
      )      
      this.setState({    
          selectedAccount: selectedAddress,        
          checkAddress: null      
      }, async () =>     
      await this.updateBalance()

в setState добавил checkAddress: null

Вот и все готово!

Давайте напомню как мы запускаем проект и посмотрим что у нас получилось.

Запускаем ноду через команду: npx hardhat node

Открываем вторую консоль

Вводим команду: npx hardhat run scripts\deploy.js --network localhost
Если ваш путь и файл отличаются то пишите свой.

Дальше переходим в папку где у вам находится frontend (у меня это папка front)
cd front

Вводим команду: npm run dev и запускаем локальный сервер

Заходим на сайт по адресу http://localhost:3000/ и смотрим что получилось

У меня выглядит как то так. Подключаем кошелек от имени овнера смарт контракта (Напомню что если вы делали все как я, то это первый из списка адресов которые выдал hardhat, когда мы запускали ноду)

После подключения мы видим что добавилась кнопка check address. Давайте нажмем.

Так как я подключился от овнера контракта то мне выдало мной адрес ура!

Давайте переключимся на другой аккаунт

Как видно мне выдало сообщение, что я не овнер и не могу посмотреть адрес.

Если не использовать try catch то будет ошибка выводиться на весь экран)

И не большой бонус.

Так как весь адрес очень большой то хочется видеть например его начало и конец, а середину нет. Давайте сделаем это.

_checkAddress = async() =>{   
   try{    
       const tx = await this.Lock.getAddress()        
       console.log(tx);        
       let currentAccaunt = ""        
       let currentAccaunt1 = ""                  
       for(let i = 0; i <= this.state.selectedAccount.length-1; i++){
          if(i <= 10 ){       
              currentAccaunt = currentAccaunt + this.state.selectedAccount[i]          
          }
          if(i > this.state.selectedAccount.length - 5 && i > this.state.selectedAccount.length - 9){     
              currentAccaunt1 = currentAccaunt1 + this.state.selectedAccount[i]          
          }          
       }     
       let Account = currentAccaunt + "..." + currentAccaunt1    
       this.setState({     
            checkAddress: Account        
       })   
   }catch{    
       console.log("not an owner!");        
       this.setState({     
            checkAddress: "not an owner!"       
       })      
   }    
}

Обычный цикл for которые бежит по нашему адресу и перезаписывает его в два новых, но только его часть. Думаю если вы дошли до сюда объяснять принцип работы нет смысла.

Еще можно при выводе баланса сделать так:

<p className={styles.balance}>balance: 
{ethers.utils.formatEther(this.state.balance).slice(0,10)} ETH</p>}

Я добавил slice(0,10) то есть из нашего баланса будут выводиться только первые 10 чисел. Грубо говоря если у нас баланс кошелька 0.03024024940946496 ETH, то зачастую нет смысла выводить полный баланс и мы его округляем до 0.030240249 так на много удобнее я считаю.

На этом все. Надеюсь кому то это поможет в реализации своих идей и проектов. Дальше больше. Будет еще статьи по этой теме. Еще сложнее и еще интереснее.


tg: мой телеграмчик)

github:
этот проект на гитхабе
все файлы из папки front в отдельном репозитории
репозиторий попки front