🇵🇹
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
  • Descrição​
  • Usage​
  • Análise​
  • Interacting with the Contract Executor​
  • Eventos​
  • Exemplo: Flipper​

Was this helpful?

  1. Developers
  2. Para Desenvolvedores
  3. Smart Contract Ink! 4.x
  4. Macros e Atributos

#[ink::contract]

Last updated 1 year ago

Was this helpful?

A macro #[ink::contract] é o ponto de entrada para escrever contratos inteligentes ink!.

Se você é um iniciante que está tentando aprender ink!, recomendamos que você dê uma olhada no nosso extenso .

Descrição

The macro does analysis on the provided smart contract code and generates proper code.

Usage

Argumentos do cabeçalho

A macro #[ink::contract] pode receber argumentos de cabeçalho adicionais separados por vírgulas:

compile_as_dependency: bool

Indica ao gerador de código ink! para sempre compilar ou nunca compilar o smart contract como se fosse usado como uma dependência de outro smart contract ink!.

Normalmente, essa sinalização só é realmente útil para desenvolvedores ink! que desejam inspecionar a geração de código de smart contracts ink!. O autor não tem conhecimento de nenhum caso de uso prático específico para usuários que faça uso desse sinalizador, mas os escritores de contratos são encorajados a refutar essa afirmação.

Observe que é recomendado usar o recurso embutido da crate ink-as-dependency para marcar as dependências de smart contracts listadas no Cargo.toml de um contrato como dependências reais para ink!.

Exemplo de Uso:

#[ink::contract(compile_as_dependency = true)]
mod my_contract {
    #[ink(storage)]
    pub struct MyStorage;

    impl MyStorage {
        #[ink(constructor)]
        pub fn construct() -> Self { MyStorage {} }

        #[ink(message)]
        pub fn message(&self) {}
    }
    // ...
}

Valor padrão: Dependente da propagação do recurso do arquivo Cargo.toml.

Indica ao gerador de código ink! qual ambiente utilizar para o smart contract ink!. O ambiente deve implementar o traço Environment (definido em ink_env) e fornecer todas as definições de tipos fundamentais necessárias, como Balance, AccountId, etc.

Ao usar uma implementação personalizada de Environment para um smart contract, todos os tipos que ele expõe para o smart contract ink! e os tipos espelhados usados no tempo de execução devem estar alinhados em relação à codificação SCALE e semântica.

Usage Example:

Dada uma implementação personalizada do ambiente Environment:

pub struct MyEnvironment;

impl ink::env::Environment for MyEnvironment {
    const MAX_EVENT_TOPICS: usize = 3;

    type AccountId = u64;
    type Balance = u128;
    type Hash = [u8; 32];
    type Timestamp = u64;
    type BlockNumber = u32;
    type ChainExtension = ::ink::env::NoChainExtension;
}

Um usuário pode implementar seu contrato ink! usando a implementação personalizada do Ambiente conforme demonstrado abaixo:

#[ink::contract(env = MyEnvironment)]
mod my_contract {
    pub struct MyEnvironment;

    impl ink::env::Environment for MyEnvironment {
        const MAX_EVENT_TOPICS: usize = 3;
        type AccountId = u64;
        type Balance = u128;
        type Hash = [u8; 32];
        type Timestamp = u64;
        type BlockNumber = u32;
        type ChainExtension = ::ink::env::NoChainExtension;
    }

    #[ink(storage)]
    pub struct MyStorage;

    impl MyStorage {
        #[ink(constructor)]
        pub fn construct() -> Self { MyStorage {} }

        #[ink(message)]
        pub fn message(&self) {}
    }
    // ...
}

Valor padrão: DefaultEnvironment definido no pacote ink_env.

A macro #[ink::contract] realiza uma análise completa do contrato inteligente de entrada em relação a argumentos inválidos e estrutura.

Algumas regras de exemplo incluem, mas não se limitam a:

  • Deve haver exatamente uma estrutura #[ink(storage)]. Essa estrutura define o layout do armazenamento em que o contrato inteligente ink! opera. O usuário pode utilizar uma variedade de recursos integrados, combiná-los de várias maneiras ou até mesmo fornecer suas próprias implementações de estruturas de dados de armazenamento. Para mais informações, visite a documentação do crate ink_storage.

Exemplo:

#[ink::contract]
mod flipper {
    #[ink(storage)]
    pub struct Flipper {
        value: bool,
    }

    impl Flipper {
        #[ink(constructor)]
        pub fn construct() -> Self { Flipper { value: false } }

        #[ink(message)]
        pub fn message(&self) {}
    }
}
  • Deve haver pelo menos um método #[ink(constructor)] definido. Os métodos marcados com #[ink(constructor)] são especiais, pois são despacháveis ​​ao instanciar o contrato. Um contrato pode definir vários construtores desse tipo, o que permite que os usuários do contrato instanciem o contrato de várias maneiras diferentes.

Exemplo: Dada a definição do contrato Flipper acima, adicionamos um #[ink(constructor)] da seguinte maneira:

#[ink::contract]
mod flipper {
    #[ink(storage)]
    pub struct Flipper {
        value: bool,
    }

    impl Flipper {
        #[ink(constructor)]
        pub fn new(initial_value: bool) -> Self {
            Flipper { value: false }
        }

        #[ink(message)]
        pub fn message(&self) {}
    }
}
  • Deve haver pelo menos um método #[ink(message)] definido. Os métodos marcados com #[ink(message)] são especiais, pois são despacháveis ​​ao invocar o contrato. O conjunto de mensagens ink! definidas para um contrato ink! define a sua interface de programação de aplicação (API), com a qual os usuários podem interagir. Um contrato ink! pode ter vários métodos ink! definidos.

Nota: Uma mensagem ink! com um receptor &self só pode ler o estado, enquanto uma mensagem ink! com um receptor &mut self pode alterar o armazenamento do contrato.

Exemplo

Dado a definição do contrato Flipper acima, adicionamos algumas definições #[ink(message)] da seguinte forma:

#[ink::contract]
mod flipper {
    #[ink(storage)]
    pub struct Flipper {
        value: bool,
    }

    impl Flipper {
        #[ink(constructor)]
        pub fn new(initial_value: bool) -> Self {
            Flipper { value: false }
        }

        /// Flips the current value.
        #[ink(message)]
        pub fn flip(&mut self) {
            self.value = !self.value;
        }

        /// Returns the current value.
        #[ink(message)]
        pub fn get(&self) -> bool {
            self.value
        }
    }
}

Mensagens Pagáveis:

Uma mensagem ink! por padrão rejeitará chamadas que adicionem fundos ao contrato inteligente. Os autores de contratos ink! podem tornar uma mensagem ink! pagável adicionando o sinalizador "payable" a ela. Um exemplo abaixo:

Observe que os construtores ink! são sempre implicitamente pagáveis e, portanto, não podem ser marcados como tal.

#[ink::contract]
mod flipper {
    #[ink(storage)]
    pub struct Flipper {
        value: bool,
    }

    impl Flipper {
        #[ink(constructor)]
        pub fn new(initial_value: bool) -> Self {
            Flipper { value: false }
        }

        /// Flips the current value.
        #[ink(message)]
        #[ink(payable)] // You can either specify payable out-of-line.
        pub fn flip(&mut self) {
            self.value = !self.value;
        }

        /// Returns the current value.
        #[ink(message, payable)] // ...or specify payable inline.
        pub fn get(&self) -> bool {
            self.value
        }
    }
}

Controlando o seletor das mensagens:

Cada mensagem e construtor do ink! possui um seletor único que identifica de forma exclusiva a mensagem ou o construtor dentro do smart contract ink!. Esses seletores são usados principalmente para direcionar a chamada do contrato ao executá-lo.

O autor de um smart contract ink! pode controlar o seletor de uma mensagem ou construtor usando a flag selector. Um exemplo é mostrado abaixo:

#[ink::contract]
mod flipper {
    #[ink(storage)]
    pub struct Flipper {
        value: bool,
    }

    impl Flipper {
        #[ink(constructor)]
        #[ink(selector = "0xDEADBEEF")] // Works on constructors as well.
        pub fn new(initial_value: bool) -> Self {
            Flipper { value: false }
        }

        /// Flips the current value.
        #[ink(message)]
        #[ink(selector = "0xCAFEBABE")] // You can either specify selector out-of-line.
        pub fn flip(&mut self) {
            self.value = !self.value;
        }

        /// Returns the current value.
        #[ink(message, selector = "0xFEEDBEEF")] // ...or specify selector inline.
        pub fn get(&self) -> bool {
            self.value
        }
    }
}

A crate ink_env fornece recursos para interagir com o executor do contrato que conecta os contratos inteligentes ink! com o mundo exterior.

Por exemplo, é possível consultar o chamador da chamada atual através de:

use ink_env;
ink::env::test::run_test::<ink::env::DefaultEnvironment, _>(|_| {
    let caller = ink::env::caller::<ink::env::DefaultEnvironment>();
    let _caller = caller;
    Ok(())
}).unwrap();

No entanto, ink! fornece uma maneira muito mais simples de interagir com o executor do contrato por meio do seu acessor de ambiente. Um exemplo abaixo:

#[ink::contract]
mod greeter {
    #[ink(storage)]
    pub struct Greeter;

    impl Greeter {
        #[ink(constructor)]
        pub fn new() -> Self {
            let caller = Self::env().caller();
            let message = format!("thanks for instantiation {:?}", caller);
            ink::env::debug_println(&message);
            Greeter {}
        }

        #[ink(message, payable)]
        pub fn fund(&mut self) {
            let caller = self.env().caller();
            let value = self.env().transferred_balance();
            let message = format!("thanks for the funding of {:?} from {:?}", value, caller);
            ink::env::debug_println(&message);
        }
    }
}

Um contrato inteligente ink! pode definir eventos que podem ser emitidos durante a execução do contrato. A emissão de eventos pode ser usada por ferramentas de terceiros para consultar informações sobre a execução e estado de um contrato.

O exemplo a seguir mostra um contrato ink! que define e emite um evento "Transferred" no #[ink(constructor)].

 #[ink::contract]
 mod erc20 {
     /// Defines an event that is emitted every time value is transferred.
     #[ink(event)]
     pub struct Transferred {
         from: Option<AccountId>,
         to: Option<AccountId>,
         value: Balance,
     }

     #[ink(storage)]
     pub struct Erc20 {
         total_supply: Balance,
         // more fields ...
     }

     impl Erc20 {
         #[ink(constructor)]
         pub fn new(initial_supply: Balance) -> Self {
             let caller = Self::env().caller();
             Self::env().emit_event(Transferred {
                 from: None,
                 to: Some(caller),
                 value: initial_supply,
             });
             Self { total_supply: initial_supply }
         }

         #[ink(message)]
         pub fn total_supply(&self) -> Balance {
             self.total_supply
         }
     }
 }

Neste exemplo, o módulo erc20 define um contrato inteligente ink! para uma token ERC20 básica. O evento "Transferred" é definido como uma estrutura que contém informações sobre o remetente, destinatário e valor transferido. No construtor, o evento é emitido quando o contrato é instanciado, informando que uma transferência ocorreu do endereço do contrato para o endereço do chamador. O contrato também possui um método total_supply que retorna o valor total de fornecimento do token.

O código abaixo mostra a implementação completa do contrato inteligente Flipper ink!. Para nós, ele funciona como o "Olá, mundo!" dos contratos inteligentes ink!, pois é mínimo, mas ainda fornece alguma funcionalidade mais ou menos útil.

Ele controla um único valor bool que pode ser false ou true e permite que o usuário inverta esse valor usando a mensagem Flipper::flip ou recupere o valor atual usando Flipper::get.

#[ink::contract]
pub mod flipper {
    #[ink(storage)]
    pub struct Flipper {
        value: bool,
    }

    impl Flipper {
        /// Creates a new flipper smart contract initialized with the given value.
        #[ink(constructor)]
        pub fn new(init_value: bool) -> Self {
            Self { value: init_value }
        }

        /// Flips the current value of the Flipper's bool.
        #[ink(message)]
        pub fn flip(&mut self) {
            self.value = !self.value;
        }

        /// Returns the current value of the Flipper's bool.
        #[ink(message)]
        pub fn get(&self) -> bool {
            self.value
        }
    }
}

O código abaixo mostra a implementação completa do contrato inteligente ink! chamado Flipper. Para nós, ele atua como o "Olá, mundo!" dos contratos inteligentes ink!, pois é mínimo, mas ainda fornece alguma funcionalidade mais ou menos útil. Ele controla um único valor booleano que pode ser falso ou verdadeiro e permite que o usuário inverta esse valor usando a mensagem Flipper::flip ou obtenha o valor atual usando a mensagem Flipper::get.

env: impl Environment

Análise

Interacting with the Contract Executor

Eventos

Exemplo: Flipper

🖥️
📑
🎙️
📇
workshop de ink!
​
​
​
​
​
​
​
​
​