🇵🇹
DAO Lunes Labs - PT
  • 👋Seja Bem-vindo a DAO Lunes Labs
  • Overview
    • 🚪Introdução
    • 🚀Manifesto DAO Lunes Labs
    • 🍕Tokenomics
    • 👑Proposta de Valor
    • 🧑‍🚀Comunidade e Participação
    • 🗺️Roadmap
    • 💼Compromisso com Ética e Responsabilidade
    • 👾Programa de Bug Bounty: Lunes Security Initiative (LSI)
  • Developers
    • 💽Para Nodes
      • 🥾Instalar Node
        • 🏗️Rust toolchain
        • 🐧Linux
    • 🖥️Para Desenvolvedores
      • 📑Smart Contract Ink! 4.x
        • ✨Configuração
          • 📐Criando um projeto com ink!
          • 🖥️Compile Seu Contrato
          • ⛓️Executar um nó Lunes
          • ⬆️Implante seu contrato
          • 🔛Chame Seu Contrato
          • 🛠️Solução de problemas
        • 🪄Fundamentos
          • 👾Modelo de Contrato
          • 👨‍🚀Armazenando Valores
          • 🔭Lendo Valores do Armazenamento
          • 🦸‍♂️Alterando os Valores de Armazenamento
          • 🎡Eventos
          • 👨‍🔧Seletores
          • 🪶Definições de Trait
          • 🗣️Chamadas entre Contratos (Cross-Contract Calls)
          • 🦸Contratos Atualizáveis
          • 🤺Funções do Ambiente
          • 🏟️Tipos de Ambiente de Cadeia
          • 💠Metadados
          • 🧪Testes de Contrato
          • 🕵️‍♂️Depuração de Contratos
          • 🔬Verificação de Contrato
        • 🎙️Macros e Atributos
          • 📇#[ink::contract]
          • 👽#[ink(anonymous)]
          • 👷#[ink(constructor)]
          • 📏#[ink(default)]
          • 🎢#[ink(event)]
          • 🛩️#[ink(impl)]
          • 📧#[ink(message)]
          • 👨‍💼#[ink(namespace = "…")]
          • 💸#[ink(payable)]
          • ⚡#[ink(selector = S:u32)]
          • 💽#[ink(storage)]
          • 💣#[ink(topic)]
          • ⛓️#[ink::chain_extension]
        • 💽Storege & Data Structires
          • Working with Mapping
          • Storage Layout
          • Custom Data Structures
          • Metadata Format
        • 👾Frontend Development
          • Getting Started
          • Connect Wallet
          • Hooks
            • All Hooks
            • Contracts
              • useCall
              • useCallSubscription
              • useContract
              • useDryRun
              • useEventSubscription
              • useEvents
              • useTx
              • useTxPaymentInfo
            • Wallets
              • useWallet
              • useAllWallets
              • useInstalledWallets
              • useUninstalledWallets
            • API
              • useApi
              • useBalance
              • useBlockHeader
          • Configuration
          • useink / core
            • Contracts
              • Call
              • decodeCallResult
              • decodeError
              • getRegistryError
              • toAbiMessage
          • useink / chains
            • Getting Started
            • Chain Configurations
            • ChainId
          • useink / notifications
            • Getting Started
            • Configuration
            • useNotifications
            • toNotificationLevel
          • useink / utils
            • Getting Started
            • Pick Helpers
            • tx Helpers
            • Types
        • 💡Examples
          • 📔Smart Contracts
          • 📱Dapps
        • 🛠️Tools
          • 🖌️OpenBrush
      • 📒Smart Contract - EVM
        • Create ERC-20 Ink Token!
      • 💰Desenvolvendo uma Wallet Lunes
        • 👾Transações de Tokens PSP22
    • 🎨Para Designers
      • 🖌️Brand Lunes
Powered by GitBook
On this page
  • Usage​
  • Calling with a default caller address​
  • Handling Result<T, E> responses from an ink! contract​
  • Return Value​

Was this helpful?

  1. Developers
  2. Para Desenvolvedores
  3. Smart Contract Ink! 4.x
  4. Frontend Development
  5. Hooks
  6. Contracts

useCall

Last updated 1 year ago

Was this helpful?

A hook for calling a contract message and decoding a successful response or receiving an error. See for compatible functions that work well with this hook.

Usage

import { useCall } from 'useink'
import { pickDecoded } from 'useink/utils'
import metadata from 'contract/metadata.json'

const CONTRACT_ADDRESS = '...'

// We define a response type so that `get.result.value.decoded` is of type SuccessfulResponse
interface SuccessfulResponse {
  foo: 'bar'
}

export const MyContractView: React.FC = () => {
  const contract = useContract(CONTRACT_ADDRESS, metadata, 'astar');
  const get = useCall<SuccessfulResponse>(contract, 'get');
  const args = ['arg-1', 2];

  return (
    <>
      <h1>Get the Result the hard way: {get.result?.ok ? get.result.value.decoded.foo : '--'}</h1>
      <h1>Or the easy way: {pickDecoded(get.result)?.foo || '--'}</h1>

      <button disabled={get.isSubmitting} onClick={() => get.send(args)}>
        Get Result
      </button>
    </>
  );
}
const call = useCall(contract, 'get');
const args = [];

call.send(args, { defaultCaller: true })

One of the benefits of using ink! is ability to return meaningful errors with Result<T, E> (since ink! v4.0.0). In this example we will distinguish between two kinds of errors and a successful result. Let's say that you have the following ink! code in your contract.

    use ink::prelude::string::String;

    // ...other contract code omitted

    #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)]
    #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
    pub struct Unhappy {
        boo: String,
    }

    // A successful response
    #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)]
    #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
    pub struct Happy {
        yippee: String,
    }

    #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)]
    #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
    pub enum Error {
        Sad(Unhappy),
    }

    impl MyMoodyContract {
      #[ink(message)]
      pub fn mood(&self, value: u64) -> Result<Happy, Error> {
          if value % 2 == 0 {
              return Ok(Happy {
                  yippee: String::from("😃"),
              });
          }

          Err(Error::Sad(Unhappy {
              boo: String::from("😢"),
          }))
      }
    }

In this example, when you call mood(2), you will get an Ok response. If you call mood(1) you will get an Err. If you call mood(5) you will get another type of Err.

Here is how we could handle the view using useink.

import { useCall, useContract, useBlockNumber, decodeError } from 'useink'
import metadata from 'contract/metadata.json'
const CONTRACT_ADDRESS = '...'

// We define the interface for the response.
interface MoodResult { 
  Ok?: { yippee: string }; 
  Err?: { 
    Sad?: { boo: string; },
  },
};

export const MyFickleContract: React.FC = () => {
  const { blockNumber } = useBlockNumber();
  const contract = useContract(CONTRACT_ADDRESS, metadata);
  const getMood = useCall<MoodResult>(contract, 'mood');

  // Fetch the mood of the contract on each new block
  useEffect(() => {
    if(blockNumber) getMood.send([blockNumber]);
  }, [blockNumber])

  // result is undefined before it is called the first time
  if (!getMood.result) return <h1>Loading...</h1>

  // if result.ok is false then one of two things happened.
  // One possibility is that a pallet in the Substrate runtime threw an error.
  // A second possibility is a contract method may have called panic! 
  // OR called assert! and it failed. In these situations no Response has been returned. 
  // We need to handle the error using decodeError.
  if (!getMood.result.ok) {
    return (
      <div>
        <p>An error occurred in runtime, not our contract function.</p>
        <p>
          {decodeError(getMood, {
            ContractTrapped: 'This is a custom message. Something went wrong.', 
          })}
        </p>
      </div>
    )
  }

  // We now know we have decoded value of type `MoodResult`
  const { decoded } = getMood.result.value;

  return (
    <h1>
      Block Number {blockNumber} makes me feel
      {decoded.Ok && decoded.Ok.yippee}
      {decoded.Err?.Sad && decoded.Err.Sad.boo}
    </h1>
  );
}
type DecodedContractResult<T> = {
  result?: {
    ok: true;
    value: {
      decoded: T; // The response is decoded using contract Metadata and of type `T`
      raw: ContractExecResult; // encoded raw data 
    } | {
      ok: false;
      // error
      // This error occurs if any pallet throws an error, 
      // or if a contract method calls panic! or assert!() and it fails.
      error: DispatchError | undefined; 
    }
  }
}

// useCall returns
{
  isSubmitting: boolean;
  // args: a list of arguments your contract message receives
  // options: additional option overrides
  // caller: the calling address. This can be used in ink! contracts with `self.env.caller()`
  //         `caller` defaults to the connected wallet address.
  send: (args?: unknown[], options?: ContractOptions, caller?: string) => 
    Promise<DecodedContractResult<T> | undefined>;
  result?: DecodedContractResult<T>;
}

Calling with a default caller address

You must first define a default caller in , then call the contract with options:

Handling Result<T, E> responses from an ink! contract

Return Value

🖥️
📑
👾
useink/utils helpers
​
​
configuration
​
​