Visibilidade, Interfaces e Funções Pagáveis

porMatheusem20/05/2022

Nesse artigo iremos abordar sobre como interagir com interfaces, funções pagáveis e níveis de visibilidade em funções do seu contrato inteligente. Falaremos sobre visibility, interface e payable.

Visibility (Visibilidade)

Funções e variáveis de estado devem declarar se são acessíveis por outros contratos.

As funções podem ser declaradas como:

  • public - pode ser chamada por qualquer contrato, endereços e contas
  • private - pode ser chamada apenas dentro do contrato que a definiu
  • internal - pode ser chamada apenas dentro do contrato que herda uma função internal
  • external - pode ser chamada apenas fora do contrato, por outros contratos, endereços e contas

As variáveis de estado podem ser declaradas como public, private ou internal mas não external.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract Base {
// A função privada só pode ser chamada
// de dentro deste contrato
// Os contratos que herdam esse contrato não podem chamar essa função.
function privateFunc() private pure returns (string memory) {
return "função privada chamada";
}
function testPrivateFunc() public pure returns (string memory) {
return privateFunc();
}
// A função interna pode ser chamada
// - dentro deste contrato
// - dentro de contratos que herdam este contrato
function internalFunc() internal pure returns (string memory) {
return "função interna chamada";
}
function testInternalFunc() public pure virtual returns (string memory) {
return internalFunc();
}
// Funções públicas podem ser chamadas
// - dentro deste contrato
// - dentro de contratos que herdam este contrato
// - por outros contratos, endereços e contas
function publicFunc() public pure returns (string memory) {
return "função pública chamada";
}
// Funções externas só podem ser chamadas
// - por outros contratos, endereços e contas
function externalFunc() external pure returns (string memory) {
return "função externa chamada";
}
// Esta função não irá compilar pois estamos tentando chamar
// uma função externa aqui.
// function testExternalFunc() public pure returns (string memory) {
// return externalFunc();
// }
// Variáveis de estado
string private privateVar = "variável privada";
string internal internalVar = "variável interna";
string public publicVar = "variável pública";
// As variáveis de estado não podem ser externas,
// portanto, esse código não será compilado.
// string external externalVar = "my external variable";
}
contract Child is Base {
// Os contratos herdados não têm acesso
// a funções privadas e variáveis de estado.
// function testPrivateFunc() public pure returns (string memory) {
// return privateFunc();
// }
// Chamada de função interna podem ser
// realizadas dentro de contratos filho.
function testInternalFunc() public pure override returns (string memory) {
return internalFunc();
}
}

Interface

Você pode interagir com outros contratos através da declaração de uma Interface.

Interface

  • não pode ter nenhuma função implementada
  • pode herdar de outras interfaces
  • todas as funções declaradas devem ser externas
  • não pode declarar um construtor
  • não pode declarar variáveis de estado
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract Counter {
uint public count;
function increment() external {
count += 1;
}
}
// Declaramos a Interface ICounter
// Através dela podemos acessar as funções count e increment
interface ICounter {
function count() external view returns (uint);
function increment() external;
}
contract MyContract {
function incrementCounter(address _counter) external {
ICounter(_counter).increment();
}
function getCount(address _counter) external view returns (uint) {
return ICounter(_counter).count();
}
}
// Exemplo utilizando o Uniswap
// Declaração da Interface UniswapV2Factory
// Através dela podemos acessar a função getPair
interface UniswapV2Factory {
function getPair(address tokenA, address tokenB)
external
view
returns (address pair);
}
// Declaração da Interface UniswapV2Pair
// Através dela podemos acessar a função getReserves
interface UniswapV2Pair {
function getReserves()
external
view
returns (
uint112 reserve0,
uint112 reserve1,
uint32 blockTimestampLast
);
}
// Declaração do Contrato UniswapExample
// No contrato abaixo podemos ver a interação
// do contrato com as duas Interfaces acima
contract UniswapExample {
address private factory = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
address private dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address private weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
function getTokenReserves() external view returns (uint, uint) {
// Aqui utilizamos a Interface UniswapV2Factory para obter
// o endereço do contrato do par dai e weth através da função getPair
address pair = UniswapV2Factory(factory).getPair(dai, weth);
// Aqui utilizamos a Interface UniswapV2Pair para obter os dois
// valores uint, reserve0 e reserve1 através da função getReserves
(uint reserve0, uint reserve1, ) = UniswapV2Pair(pair).getReserves();
return (reserve0, reserve1);
}
}

Payable (Pagável)

Funções e endereços declarados como payable podem receber ether.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract Payable {
// Endereço definido com payable poderá receber Ether
address payable public owner;
// Construtor definido com payable poderá receber Ether
constructor() payable {
owner = payable(msg.sender);
}
// Função para depositar Ether neste contrato.
// Chame esta função junto com algum Ether.
// O saldo deste contrato será atualizado automaticamente.
function deposit() public payable {}
// Chame esta função junto com algum Ether.
// A função lançará um erro, pois esta função não é pagável.
function notPayable() public {}
// Função para retirar todo o Ether deste contrato.
function withdraw() public {
// obtém a quantidade de Ether armazenada neste contrato
uint amount = address(this).balance;
// enviar todo o Ether para o proprietário
// O dono do contrato pode receber Ether desde que o
// endereço esteja definido com payable
(bool success, ) = owner.call{value: amount}("");
require(success, "Falha ao enviar Ether");
}
// Função para transferir Ether deste contrato para o endereço de entrada
function transfer(address payable _to, uint _amount) public {
// Observe que "to" é declarado como pagável 'payable'
(bool success, ) = _to.call{value: _amount}("");
require(success, "Falha ao enviar Ether");
}
}

Testar no Remix