O Solidity é usado para criar contratos in­te­li­gen­tes complexos pro­je­ta­dos para operar no Ethereum block­chain**. Essa linguagem apresenta es­tra­té­gias ex­clu­si­vas que a di­fe­ren­ciam de outras lin­gua­gens de pro­gra­ma­ção.

O que é Solidity?

Solidity é uma linguagem de pro­gra­ma­ção de alto nível para a criação de contratos in­te­li­gen­tes na block­chain da Ethereum. Os contratos in­te­li­gen­tes são contratos au­to­e­xe­cu­tá­veis que au­to­ma­ti­zam a troca de ativos entre as partes. O que há de especial neles é que não são ne­ces­sá­rios in­ter­me­diá­rios para garantir a con­for­mi­dade com o contrato in­te­li­gente.

Solidity source code é compilado em bytecode e im­plan­tado no block­chain da Ethereum como um contrato in­te­li­gente. Uma vez concluído, o contrato in­te­li­gente pode ser executado por qualquer nó da rede, e o estado é ar­ma­ze­nado no block­chain. Mostramos um exemplo de um contrato simples que modela uma máquina de venda au­to­má­tica de NFT:

pragma Solidity 0.8.7;
contract NFTVendingMachine {
    // Declare state variables
    address public owner;
    mapping (address => uint) public nftBalance;
    // Run on deployment
    constructor() {
        owner = msg.sender;
        nftBalance[address(this)] = 100;
    }
    // Allow the owner to restock the NFT balance
    function restock(uint amount) public {
        require(msg.sender == owner, "Only the owner can restock.");
        nftBalance[address(this)] += amount;
    }
    // Allow anyone to purchase NFTs
    function purchase(uint amount) public payable {
        require(msg.value >= amount * 1 ether, "You must pay at least 1 ETH per NFT");
        require(nftBalance[address(this)] >= amount, "Not enough NFTs in stock to complete this purchase");
        nftBalance[address(this)] -= amount;
        nftBalance[msg.sender] += amount;
    }
}
solidity

Para quais apli­ca­ti­vos o Solidity é adequado?

O Solidity foi projetado es­pe­ci­fi­ca­mente para criar apli­ca­ti­vos dis­tri­buí­dos ou DApps exe­cu­ta­dos na Máquina Virtual Ethereum (EVM). Os contratos in­te­li­gen­tes são adequados para gerenciar ativos digitais, criar trocas des­cen­tra­li­za­das e im­ple­men­tar sistemas de votação, entre outras coisas.

Finanças des­cen­tra­li­za­das (DeFi)

O Solidity está sendo usado para de­sen­vol­ver apli­ca­ti­vos DeFi, tais como câmbios des­cen­tra­li­za­dos, pla­ta­for­mas de crédito e em­prés­timo, mercados de previsão e cryp­to­cur­ren­cies. O DeFi se tornou um dos casos de uso mais populares da tec­no­lo­gia block­chain. Nesse processo, o Solidity se tornou uma fer­ra­menta in­dis­pen­sá­vel para a criação de apli­ca­ti­vos DeFi na rede Ethereum.

Tokens não fungíveis

O non-fungible token (NFT), tem des­fru­tado de grande po­pu­la­ri­dade desde a década de 2020. Os NFTs são ativos digitais ex­clu­si­vos ar­ma­ze­na­dos no block­chain. Eles podem ser obras de arte digital, me­mo­ra­bi­lia esportiva ou artefatos do setor de jogos. O Solidity é usado para criar os contratos in­te­li­gen­tes que alimentam os NFTs.

Ge­ren­ci­a­mento da cadeia de entrega

O Solidity pode ser usado para criar contratos in­te­li­gen­tes para monitorar e gerenciar cadeias de su­pri­men­tos. Os contratos são usados para au­to­ma­ti­zar vários processos da cadeia de su­pri­men­tos. Isso inclui o ras­tre­a­mento da mo­vi­men­ta­ção de mer­ca­do­rias, a ve­ri­fi­ca­ção da au­ten­ti­ci­dade dos produtos e o pro­ces­sa­mento de pa­ga­men­tos entre as partes.

Sistemas de re­con­ci­li­a­ção

O Solidity pode ser usado para criar contratos in­te­li­gen­tes que im­ple­men­tam sistemas de votação seguros e trans­pa­ren­tes no block­chain. Os contratos podem ser usados para garantir que os votos sejam contados cor­re­ta­mente e que o processo de votação seja justo e trans­pa­rente.

Quais são os prós e os contras do Solidity?

Embora a Solidity seja uma linguagem poderosa para a criação de contratos in­te­li­gen­tes no block­chain da Ethereum, ela tem suas vantagens e des­van­ta­gens es­pe­cí­fi­cas que os de­sen­vol­ve­do­res devem con­si­de­rar ao de­sen­vol­ver contratos in­te­li­gen­tes. No entanto, a criação de contratos in­te­li­gen­tes seguros exige um nível es­pe­cí­fico de pro­fi­ci­ên­cia e cautela.

Como ilus­tra­ção, abaixo está um contrato in­te­li­gente que funciona como um buraco negro. Qualquer Ether enviado para o contrato é consumido per­ma­nen­te­mente, sem pos­si­bi­li­dade de recuperar o Ether ou fazer um pagamento:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.9.0;
// This contract swallows all Ether sent to it
contract Blackhole {
    event Received(address, uint);
    receive() external payable {
            emit Received(msg.sender, msg.value);
    }
}
solidity

Vantagens da Solidez

  • Fle­xi­bi­li­dade: o Solidity é uma linguagem versátil. Ela pode ser usada para de­sen­vol­ver di­fe­ren­tes contratos in­te­li­gen­tes com uma variedade de casos de uso.
  • Segurança: o Solidity foi criado com foco na segurança, in­cor­po­rando ca­rac­te­rís­ti­cas como controles de acesso, tra­ta­mento de exceções e me­ca­nis­mos de falha para ajudar os de­sen­vol­ve­do­res a criar contratos seguros.
  • Com­pa­ti­bi­li­dade com Ethereum: Atu­al­mente, a Solidity é a linguagem preferida para a produção de contratos in­te­li­gen­tes no block­chain da Ethereum.
  • Co­mu­ni­dade distinta: Uma grande co­mu­ni­dade de de­sen­vol­ve­do­res de block­chain trabalha com o Solidity, o que resulta em uma in­fi­ni­dade de recursos para apren­di­zado e solução de problemas.

Des­van­ta­gens do Solidity

  • Curva de apren­di­zado: Para os de­sen­vol­ve­do­res que são novos no de­sen­vol­vi­mento de block­chain e contratos in­te­li­gen­tes, o Solidity tem uma curva de apren­di­zado re­la­ti­va­mente acentuada.
  • Un­chan­ge­a­bi­lity: Depois que um contrato in­te­li­gente é im­plan­tado no block­chain, ele não pode mais ser mo­di­fi­cado. Portanto, os de­sen­vol­ve­do­res precisam ser ex­tre­ma­mente cui­da­do­sos ao escrever e testar.
  • Falta de ve­ri­fi­ca­ção formal: o Solidity não tem fer­ra­men­tas in­te­gra­das para revisão formal de código. Isso exige que os de­sen­vol­ve­do­res utilizem fer­ra­men­tas externas para garantir a precisão de seus contratos.
  • Fer­ra­men­tas limitadas: o ecos­sis­tema de fer­ra­men­tas do Solidity ainda está em seus estágios iniciais, o que pode resultar em problemas com ambientes de de­sen­vol­vi­mento integrado (IDEs), es­tru­tu­ras de teste e outras fer­ra­men­tas de de­sen­vol­vi­mento.

Qual é a sintaxe básica do Solidity?

O Solidity é uma linguagem de pro­gra­ma­ção orientada a objetos projetada para contratos in­te­li­gen­tes. Ela se inspira em Ja­vaS­cript, Python e C++. A sintaxe da linguagem é se­me­lhante à do Ja­vaS­cript, embora com algumas idi­os­sin­cra­sias in­tri­gan­tes.

Variáveis no Solidity

À primeira vista, o manuseio de variáveis do Solidity pode parecer se­me­lhante ao de outras lin­gua­gens de pro­gra­ma­ção. No entanto, uma distinção fun­da­men­tal surge do fato de que a Máquina Virtual Ethereum (EVM) serve como ambiente de execução. Todas as operações no EVM, inclusive o ar­ma­ze­na­mento de dados, incorrem em uma certa quan­ti­dade de custo de “gás”. Con­se­quen­te­mente, durante a pro­gra­ma­ção, é preciso avaliar a efi­ci­ên­cia de uma operação e de­ter­mi­nar como ela pode ser im­ple­men­tada da forma mais eficiente possível.

Além das variáveis regulares, o Solidity tem cons­tan­tes, que devem ser definidas durante a com­pi­la­ção. As cons­tan­tes requerem menos gás para ar­ma­ze­na­mento:

// Regular variable can be declared without defining
int a;
// Constant needs to be defined at declaration
int constant b = 51;
solidity

O mesmo se aplica às immutable variáveis, pois elas exigem menos gás e não podem ser alteradas após a atri­bui­ção. Ao contrário das constant variáveis, a atri­bui­ção de variáveis imutáveis pode ser feita em tempo de execução.

De­cla­ra­ções de controle no Solidity

Como uma linguagem de pro­gra­ma­ção im­pe­ra­tiva, o Solidity oferece suporte a ins­tru­ções de controle fa­mi­li­a­res, como branches e loops. Mostramos o código para se­le­ci­o­nar o maior de dois números, a e b:

int largerNumber = 0;
// If-else statement
if (a > b) {
    largerNumber = a;
} else {
        largerNumber = b;
}
solidity

O for loop no Solidity cor­res­ponde à sintaxe conhecida do Ja­vaS­cript ou do C++:

// Loop 10 times
for (int i = 0; i < 10; i++) {
    // …
}
solidity

O while loop também funciona nor­mal­mente. Com­bi­na­mos uma condição de en­cer­ra­mento com uma variável de contador numérico:

bool continueLoop = true;
int counter = 0;
// Loop at most 10 times
while (continueLoop && counter < 10) {
    // …
    counter++;
}
solidity

Tipos simples no Solidity

O Solidity é uma linguagem de tipagem estática e suporta os tipos comumente en­con­tra­dos em lin­gua­gens de pro­gra­ma­ção. Os tipos simples que re­pre­sen­tam valores únicos incluem booleanos, números e strings.

Os booleanos no Solidity mapeiam os valores true e false. Eles podem ser vin­cu­la­dos usando os ope­ra­do­res booleanos co­nhe­ci­dos e usados em if de­cla­ra­ções:

bool paymentReceived = true;
bool itemsStocked = true;
bool continueTransaction = paymentReceived && itemsStocked;
if (continueTransaction) {
    // ...
}
solidity

O Solidity suporta uma ampla gama de tipos numéricos. Os números inteiros podem ser di­fe­ren­ci­a­dos entre números assinados (int) e números não assinados (uint) , sendo que o último só pode ser positivo. Além disso, o intervalo de um número pode ser es­pe­ci­fi­cado em etapas de 8 bits, de int8 via int16 até int265:

uint8 smallNumber = 120;
int8 negativeNumber = -125;
int8 result = smallNumber + negativeNumber;
assert(result == -5)
solidity

As strings são usadas no Solidity prin­ci­pal­mente para gerar mensagens de status. A linguagem suporta aspas simples e duplas , bem como ca­rac­te­res Unicode:

string message = 'Hello World';
string success = unicode"Transfer sent";
Solidity

Funções no Solidity

As funções são um aspecto fun­da­men­tal do Solidity, como na maioria das lin­gua­gens de pro­gra­ma­ção. A definição de uma função é se­me­lhante à do Ja­vaS­cript, em que os tipos de ar­gu­men­tos devem ser ex­pli­ci­ta­mente es­pe­ci­fi­ca­dos. Além disso, uma palavra-chave returns é utilizada para indicar os tipos de valores.

// Define a function
function addNumbers(int a, int b) returns (int) {
    return a + b;
}
solidity

A chamada de uma função é feita como de costume:

// Call the function
int result = addNumbers(2, 3);
solidity

É in­te­res­sante notar que, ana­lo­ga­mente aos ar­gu­men­tos nomeados, os valores de retorno no Solidity também podem ser nomeados. Nessa situação, a atri­bui­ção das variáveis cor­res­pon­den­tes no corpo da função é su­fi­ci­ente, e um retorno explícito via return é des­ne­ces­sá­rio:

function divideNumbers(int dividend, int divisor) returns (int quotient) {
    quotient = dividend / divisor;
    // No `return` necessary
}
solidity

Se­me­lhante a constant ou immutable variáveis, no Solidity as funções podem ser marcadas como não mo­di­fi­ca­do­ras de estado. As palavras-chave view e pure são usadas para essa fi­na­li­dade. Uma view função não altera o estado, enquanto uma pure função garante adi­ci­o­nal­mente que não lerá as variáveis de estado.

Contratos in­te­li­gen­tes no Solidity

Além dos tipos padrão, o Solidity conhece um punhado de tipos es­pe­ci­a­li­za­dos em contratos in­te­li­gen­tes. O tipo básico é address e mapeia endereços Ethereum. Os endereços que são payable podem receber trans­fe­rên­cias em Ether. Para essa fi­na­li­dade, payable os endereços fornecem balance() e transfer() métodos.

// Get address of this contract
address mine = address(this);
// Get payable external address
address payable other = payable(0x123);
// Transfer if balances fulfill conditions
if (other.balance < 10 && mine.balance >= 100) {
    other.transfer(10);
}
solidity

Com base no address tipo, o contract tipo existe como uma cons­tru­ção central da linguagem. Os contratos cor­res­pon­dem apro­xi­ma­da­mente às classes em lin­gua­gens de pro­gra­ma­ção ori­en­ta­das a objetos. Assim, os contratos agrupam dados e funções de estado e os protegem do mundo externo. Os contratos oferecem suporte à herança múltipla, como é conhecido em Python ou C++.

Os contratos ge­ral­mente começam com uma pragma linha es­pe­ci­fi­cando a versão permitida do Solidity, seguida pela definição real:

// Make sure Solidity version matches
pragma Solidity >=0.7.1 <0.9.0;
// Contract definition
contract Purchase {
    // Public state variables
    address seller;
    address buyer;
    
    // View-function
    function getSeller() external view returns (address) {
        return seller;
    }
}
solidity

Os contratos in­te­li­gen­tes podem definir dados e funções de estado. Como é sabido em C++ e Java, um dos três níveis de acesso pode ser definido em cada caso:

  • public: A variável pode ser acessada pela leitura e gravação de dentro do contrato. Além disso, uma view função é gerada au­to­ma­ti­ca­mente como um getter para acesso de leitura externa.
  • internal: a variável está protegida do acesso externo. O acesso de leitura e gravação é possível de dentro do contrato, bem como de contratos herdados.
  • private: como internal, mas não há acesso de contratos herdados

As funções podem ainda ser ca­rac­te­ri­za­das como external. Uma external função atua como parte da interface do contrato e é usada para acesso externo. A receive função para receber éter é um exemplo bem conhecido:

// Define without `function` keyword
receive() external payable {
    // Handle Ether
}
solidity

Mo­di­fi­ca­do­res no Solidity

O Solidity tem uma cons­tru­ção de linguagem in­tri­gante na forma de mo­di­fi­ca­do­res, que se as­se­me­lham aos de­co­ra­do­res do Python. Assim como no Python, os mo­di­fi­ca­do­res no Solidity são uti­li­za­dos para alterar a invocação de uma função. Elas são fre­quen­te­mente em­pre­ga­das para garantir que uma condição es­pe­cí­fica seja atendida antes da execução de uma função:

contract Sale {
    uint price;
    address payable owner;
    modifier onlyOwner {
        // Will throw error if called by anyone other than the owner
        require(
            msg.sender == owner,
            "Only owner can call this function."
        );
        // The wrapped function's body is inserted here
        _;
    }
    
    // `onlyOwner` wraps `changePrice`
    function changePrice(uint newPrice) public onlyOwner {
        // We'll only get here if the owner called this function
        price = newPrice;
    }
}
solidity

Ge­ren­ci­a­mento de tran­sa­ções com o Solidity

O Solidity tem um ge­ren­ci­a­mento de tran­sa­ções integrado. Ele pode ser usado para garantir que uma trans­fe­rên­cia de éter seja com­ple­ta­mente liquidada ou não seja liquidada. A linguagem entende a revert palavra-chave, que aciona uma “reversão” de uma transação. Com a palavra-chave error , você pode definir seus próprios códigos de erro:

// Custom error definition
error InsufficientPayment(uint256 paid, uint256 required);
// Contract representing a sale
contract Sale {
    uint price;
    // Purchase if enough ether transferred
    function purchase() public payable {
        if (msg.value < price) {
            revert InsufficientPayment(msg.value, price);
        }
        // Complete purchase
    }
}
solidity

Outro padrão en­con­trado com frequên­cia é o uso da require() função. Ela pode ser usada de forma análoga a revert:

// Using `require()` function
if (!condition) revert("Error message");
// Equivalent to
require(condition, "Error message");
solidity
Ir para o menu principal