O seguinte artigo é o primeiro de uma série de artigos para ajudá-lo a construir uma DAO na rede Flow usando a linguagem Cadence.
O que é uma Organização Autônoma Descentralizada (DAO)?
Uma organização autônoma descentralizada (DAO) é uma forma emergente de estrutura legal sem um corpo governante central e cujos membros compartilham um objetivo comum de agir no melhor interesse da entidade. Popularizadas por entusiastas de criptomoedas e tecnologia blockchain, as DAOs são usadas para a tomada de decisões em uma abordagem de gerenciamento que acontece de baixo para cima.
Como desenvolver um contrato inteligente de DAO com Cadence
Os contratos inteligentes de DAO são usados para automatizar processos e garantir que as regras sobre condições pré-definidas sejam seguidas. Eles são semelhantes aos contratos ERC20, que garantem que regras específicas sejam seguidas ao criar e gerenciar tokens, como o valor de fornecimento e detalhes de transferência. Um exemplo de um ótimo contrato inteligente de DAO seria um empreendimento que lida com grants (patrocínios). Este tipo de contrato garante que pools, votação para distribuição de fundos e distribuição de fundos ocorram de acordo com regras pré-definidas.
Neste primeiro artigo, aprenderemos como configurar um esboço de um site de uma DAO com autenticação Web3 na blockchain Flow, com um simples contrato inteligente de Guestbook (Livro de Visitas) / Whitelist (Lista de Permissões ou Lista Branca) para aqueles interessados em se inscrever para o lançamento futuro da DAO. Em seguida, teremos a base para escrever nosso próprio contrato inteligente de DAO.
Introdução à Cadence
No mundo acelerado da Web3, não há falta de novas tecnologias inovadoras para explorar. A Flow foi construída como uma alternativa a blockchains de camada 1 mais lentas e menos amigáveis ao usuário, com sua própria linguagem de contrato inteligente personalizada, conhecida por se destacar no manuseio de ativos digitais, como os NFTs. Foi construída do zero como uma alternativa melhor para os problemas de congestionamento de rede e as taxas altas da Ethereum.
A linguagem de contrato inteligente Cadence é a primeira linguagem de programação orientada a recursos que torna fácil e eficiente a criação e o gerenciamento de ativos digitais. Embora o Solidity seja excelente para facilitar a Web3 através de contratos inteligentes, há desvantagens. A Cadence melhora as falhas do Solidity fornecendo a capacidade de atualizar contratos inteligentes e recursos que reduzem o risco de erros humanos, entre outras melhorias.
Este artigo explicará a história da Flow, descompactará sua linguagem de contrato inteligente Cadence e dará exemplos de como desenvolver um pequeno Dapp com ela.
História da Flow
Em 2017, um novo jogo de colecionáveis da Ethereum, CryptoKitties, desenvolvido pela empresa canadense Dapper Labs, fez manchetes depois de causar grande congestionamento na rede Ethereum, tendo apenas 10.000 usuários. Os desenvolvedores da Dapper Labs perceberam rapidamente que a rede Ethereum não estava otimizada para operar e escalar um jogo de sucesso, então começaram a trabalhar em uma alternativa.
O resultado dos esforços da Dapper Lab é a Flow Blockchain - uma blockchain descentralizada e amigável para desenvolvedores projetada para escalar sem fragmentação (sharding). A Flow é altamente otimizada para criar e gerenciar ativos digitais, como os NFTs.
Programação Orientada a Recursos
A Cadence é uma nova linguagem de contrato inteligente introduzida pela equipe de desenvolvedores da Flow para otimizar a criação e o gerenciamento de ativos digitais na blockchain. É a primeira linguagem de alto nível com um sistema forte de tipos estáticos, usando uma sintaxe inspirada em linguagens de programação modernas. Recursos, como NFTs, são armazenados diretamente na conta do usuário, e a linguagem impõe regras estritas para o gerenciamento de ativos, reduzindo o risco de perda ou exclusão acidental de um ativo devido a erros no código.
A Whitelist, um pequeno dApp
No restante deste artigo, iremos passar pelo processo de criação de um dApp simples na blockchain Flow.
Começaremos com a configuração e implantação de um contrato inteligente de uma Whitelist. Em seguida, construiremos uma interface para conectar ao nosso contrato inteligente e interagir com ele.
A funcionalidade que construiremos permitirá aos usuários conectar suas contas Flow, criar uma conta se ainda não tiverem uma e assinar a Whitelist. Então, o dApp exibirá os endereços de todos os usuários que a assinaram, e o endereço conectado poderá ler a data em que assinou a Whitelist. Será um excelente projeto para destacar o quão fácil é começar a desenvolver contratos inteligentes na Flow e o quão eficaz é a Biblioteca de Clientes Flow (Flow Client Library, ou FCL) para interagir com a blockchain.
Para seguir este tutorial, você precisará dos seguintes itens:
Com tudo isso instalado, vamos começar!
Nosso Primeiro Contrato Inteligente
Para começar a fazer nosso primeiro Contrato Inteligente, precisamos descobrir um lugar para realmente colocá-lo! Para fazer isso, abra um navegador de sua escolha e vá para o playground da Flow, colando este URL: https://play.onflow.org. Depois de fazer isso, faça o seguinte:
- No lado esquerdo, clique na guia '0x01'.
- Exclua tudo nesta página.
Isso deve ficar assim
O que fizemos foi clicar na conta com endereço 0x01
e excluir o contrato desta conta. Isso levanta um tópico importante.
O que é um endereço?
Um endereço é algo que começa com 0x
seguido de um monte de números e letras aleatórios. Aqui está um exemplo de endereço da Flow: 0xe5a8b7f23e8b548f
. No playground da Flow, você verá endereços muito mais curtos, como 0x01
. Isso é apenas para tornar as coisas mais simples.
Mas o que realmente é um endereço? Bem, você pode pensar neles como um usuário. Quando quero fazer algo na blockchain, preciso ter uma conta. Cada conta tem um endereço associado a ela. Então, quando você vê algo como 0xe5a8b7f23e8b548f
, isso é realmente apenas a conta de uma pessoa que é usada para armazenar dados, recursos e contratos inteligentes.
Onde os contratos inteligentes vivem?
Contratos inteligentes são contas que foram implantadas. Como mencionamos acima, as contas são de propriedade de um usuário, e cada conta tem um endereço associado a ela que sempre começa com 0x
. Neste caso, como estamos no playground da Flow, ele nos deu automaticamente 5 contas, ou seja, 0x01
, 0x02
, e assim por diante. Assim, os contratos inteligentes vivem em um endereço. Então, quando implantamos um contrato chamado Hello World
na conta 0x01
, é assim que o identificamos. Se quisermos interagir com ele, teríamos que saber tanto o nome do contrato quanto o endereço. Veremos isso com mais profundidade quando importarmos coisas mais tarde.
Voltando para a Whitelist
Nesse caso, implantaremos nosso contrato inteligente da Whitelist na conta 0x01
. Isso significa que a conta 0x01
é a proprietária deste contrato inteligente. No mundo real, você implantaria seu contrato inteligente em sua conta, mas como este é um mundo de simulação falsa, podemos escolher qualquer conta que quisermos, então escolhemos 0x01
.
Vamos fazer nosso contrato agora. No espaço vazio, digite o seguinte:
pub contract Whitelist {
init () {
}
}
Contrato inteligente Cadence
A parte do contrato pub
[nome do contrato] sempre será o que você digita ao criar um novo contrato. Você pode preencher o nome do contrato com o que quiser chamar seu contrato.
A função init()
é uma função que todo contrato deve ter. Ela é chamada quando o contrato é inicialmente implantado, o que no mundo real, só acontece uma vez.
E assim, temos um contrato inteligente na Flow. No entanto, ele ainda não faz nada, então vamos fazer ele armazenar uma variável addressInfo
para podermos armazenar alguns dados neste contrato.
Modifique seu código de contrato para que ele fique assim:
pub contract Whitelist {
// Informações do contrato
pub var addressInfo: {Address: UFix64}
init () {
self.addressInfo = {}
}
}
Adicionando variável pública addressInfo
Na Cadence, ao declarar uma variável, você deve seguir este formato:
[modificador de acesso] [var/let] [nome da variável]: [tipo]
Usando o exemplo acima…
- Nosso modificador de acesso é
pub
, o que significa que qualquer pessoa pode ler esta variável. -
var
significa que essa variável não é uma constante e pode ser alterada. Se você quiser definir um valor que nunca deve ser alterado, uselet
em vez disso. - O nome da função é
addressInfo
. - O tipo da nossa variável é um Dicionário. Um dicionário é algo que mapeia uma chave para um valor. No exemplo acima, mapeamos
Addresses
(endereços) paraUFix64s
. Mais especificamente, mapeamos o endereço da conta de alguém para o momento exato em que eles assinaram a Whitelist. Fizemos isso com o tipo dicionário, que é{Type: Type}
.
Agora, colocamos self.addressInfo = {}
dentro da função init()
. Lembre-se de que a função init()
é chamada quando o contrato é implantado, o que acontece apenas uma vez. self
é uma palavra-chave que significa "a variável que está um nível acima". Neste caso, self.addressInfo
refere-se à variável addressInfo
que declaramos logo acima, e a definimos como um dicionário vazio.
Agora, definimos o dicionário que irá registrar os endereços dos usuários, mas ainda não implementamos nenhuma forma de interagir com ele e permitir que as pessoas realmente se inscrevam nele. Precisamos de uma função para isso, e ela deve ser assim:
// Função pública para adicionar um novo endereço
pub fun addAddress(newAddress: Address) {
pre {
self.addressInfo[newAddress] == nil: "Este endereço já assinou!"
}
self.addressInfo[newAddress] = getCurrentBlock().timestamp
}
Adicionando nossa primeira função pública
Neste exemplo, declaramos uma função pública chamada addAddress
que recebe um parâmetro chamado newAddress
que deve ser do tipo Address
. Dentro da função há uma pré-condição; o que significa que o código a seguir será executado somente se determinadas condições forem atendidas. Neste caso, a função só será executada se a busca em nosso dicionário com o newAddress
retornar null
, o que significaria que essa conta nunca assinou a Whitelist antes. Se já o tiver feito, a função irá falhar e o processo será revertido.
Pré-condições e pós-condições devem ser definidas como a primeira coisa de uma função, e não é possível colocá-las no meio ou no final. Para que uma pré / pós-condição passe, a condição deve ser verdadeira, caso contrário, ocorrerá uma falha com a string posteriormente.
Agora, para finalizar este contrato, vamos adicionar um elemento final: eventos. Os eventos são uma maneira de um contrato inteligente comunicar ao mundo exterior que algo aconteceu.
Por exemplo, se listarmos um NFT para venda, queremos que o mundo exterior saiba que estamos vendendo aquele NFT. No nosso caso, queremos que o contrato nos informe quando ele foi inicializado e quando alguém assina a Whitelist.
Depois de adicionar esses dois eventos, o seu contrato inteligente deve ficar assim:
ContractInitialized
é um evento universal que sinaliza a implantação de um novo contrato. Por outro lado, o evento Signed
é o nosso próprio evento pessoal que nos informará quando alguém tiver assinado a Whitelist e compartilhará o endereço da conta e a data exata em que ele assinou o contrato. Agora, tudo o que precisamos fazer é clicar em "Deploy" para implantar este contrato no playground.
Agora que o nosso contrato inteligente está concluído, precisamos escrever scripts e transações para interagir com ele. Scripts são funções “somente leitura” que nos permitem visualizar dados na blockchain, sem custo! No lado esquerdo, em "Script Templates" (modelos de script), clique na guia que diz "Script" e exclua tudo dentro dela. Em seguida, escreva o seguinte código:
import Whitelist from 0x01
pub fun main(user: Address): UFix64? {
let timestamp = Whitelist.addressInfo[user]
return timestamp
}
Escrevendo nosso primeiro Script com Cadence
Este script nos permitirá ler os dados do contrato. Mais especificamente, nos dará a data em que um endereço específico assinou o contrato. Isso é o que estamos fazendo dentro dele:
- Estamos importando o contrato inteligente da Whitelist da conta
0x01
. - Estamos executando uma função pública chamada
main
, que recebe como parâmetro um usuário do tipoAddress
e pode ou não retornar umUFix64
. - Procuramos no dicionário
addressInfo
pela marca temporal (timestamp
) atribuída ao usuário (user
) e a retornamos como uma variável. Se encontrarmos a marca temporal, isso retornará umUFix64
, caso contrário; retornará zero.
Se você executar este script agora, ele não fornecerá nenhum dado porque ninguém assinou ainda! Mas como alguém poderia assinar nossa Whitelist se não escrevemos nenhuma transação para ela? As transações são funções que nos permitem escrever dados na blockchain; elas custam uma pequena taxa.
No lado esquerdo, em “Transaction Templates”, clique na guia que diz “Transaction” e exclua tudo dentro dela. Em seguida, escreva o seguinte código:
import Whitelist from 0x01
transaction {
// Configure a Variável de endereço
let address: Address
prepare(acct: AuthAccount) {
// Atribua o endereço do signatário à nossa variável de endereço
self.address = acct.address
}
execute {
// Adicione endereço à Whitelist
Whitelist.addAddress(newAddress: self.address)
}
}
Nossa primeira transação Cadence
Há algumas coisas acontecendo aqui, mas antes de abordá-las, irei explicar algo primeiro:
Na Flow, as contas podem armazenar seus próprios dados. O que isso significa? Bem, se eu possuo um NFT (Token não fungível) na Flow, esse NFT é armazenado na minha conta. Isso é muito diferente de outras blockchains como a Ethereum. Na Ethereum, seu NFT é armazenado no contrato inteligente. Na Flow, na verdade, permitimos que as contas armazenem seus próprios dados. Mas como acessamos os dados em sua conta? Podemos fazer isso com o tipo AuthAccount
. Toda vez que um usuário envia uma transação, você precisa pagar pela transação e, em seguida, "assiná-la". Tudo o que isso significa é que você clicou em um botão dizendo "Quero aprovar esta transação". Quando você assinar, a transação recebe sua AuthAccount
e pode acessar os dados em sua conta.
Você pode ver isso sendo feito na fase prepare
da transação, e esse é todo o ponto da fase prepare
: acessar as informações/dados em sua conta. Por outro lado, a fase execute
não pode fazer isso. Mas pode chamar funções e fazer coisas para alterar os dados na blockchain. OBSERVAÇÃO: Na realidade, você nunca precisa realmente da fase execute
. Tecnicamente, você pode fazer tudo na fase prepare
, mas o código fica menos claro dessa forma. É melhor separar a lógica.
Neste exemplo, o que fizemos foi muito simples:
Declaramos uma variável chamada
address
Executamos o
prepare,
solicitando que a conta conectada forneça suaAuthAccount
para que possamos acessar seu endereçoNa fase
execute
, executamos a funçãoaddAddress
dentro do contrato inteligente da Whitelist com nossa variáveladdress
que contém o endereço real da conta do usuário na blockchain.
Se implantarmos nosso contrato no Playground e executarmos a transação usando a conta 0x02
, poderemos executar nosso script com a mesma conta e ver esta mensagem:
Executando o script após assinar a Whitelist
Parabéns! Você implantou seu primeiro contrato inteligente com transações e scripts!
Agora, na vida real, você deve implantar seu contrato em um ambiente real, como as redes principais (mainnet
) ou de teste (testnet
); o playground é bom, mas há apenas algumas coisas que você pode fazer lá. É hora de implantar nosso contrato na blockchain atual da Flow, neste caso: a rede de testes.
Instalando a extensão da Cadence no VS Code
Se você ainda não instalou o VS Code, pode fazer isso aqui: https://code.visualstudio.com/
Agora que não estamos mais no playground, queremos que os erros apareçam em nosso VS Code quando estivermos codificando com a Cadence. Existe uma extensão para fazer isso!
Abra o VS Code. No lado esquerdo do VS Code, há um ícone que se parece com 4 quadrados. Clique nele e pesquise “Cadence”.
Clique na seguinte extensão e pressione “Instalar”:
Instalando a CLI da Flow e o flow.json
A CLI da Flow nos permitirá executar transações e scripts a partir do terminal e fazer outras coisas da Flow, como implantar um contrato.
Instale a CLI da Flow. Você pode fazer isso colando o seguinte no seu terminal:
.Mac
sh -ci "$(curl -fsSL https://storage.googleapis.com/flow-cli/install.sh)"
.Windows
iex "& { $(irm 'https://storage.googleapis.com/flow-cli/install.ps1') }"
.Linux
sh -ci "$(curl -fsSL https://storage.googleapis.com/flow-cli/install.sh)"
Você pode confirmar que a CLI da Flow está instalada acessando um terminal e digitando flow version
. Se uma versão aparecer, você está pronto para continuar.
Pasta da Flow
Dentro do nosso diretório-base, vamos criar uma nova pasta chamada flow
.
Dentro da pasta flow
, vamos criar outra pasta chamada cadence
.
Dentro da pasta cadence
, vamos criar uma pasta de contratos (contracts
), uma pasta de transações (transactions
) e uma pasta de scripts
.
Dentro da pasta de contratos, adicione um novo arquivo chamado NOME_DO_CONTRATO.cdc
. Substitua NOME_DO_CONTRATO
pelo nome do seu contrato, neste caso Whitelist.cdc
.
Dentro da pasta de scripts devemos fazer o mesmo. Importe get_user_timestamp.cdc
como:
import Whitelist from "../../contracts/Whitelist.cdc"
pub fun main(user: Address): UFix64? {
let timestamp = Whitelist.addressInfo[user]
return timestamp
}
Importando o contrato inteligente Whitelist para nosso Script
Observe que as importações também estão todas erradas. Não estamos mais importando de 0x01
, isso foi apenas uma brincadeira do playground. Neste caso, estamos importando de um contrato local existente em nosso projeto. Portanto, altere as importações para algo como este formato:
import Whitelist from "../contracts/Whitelist.cdc"
Dentro da pasta de transações, importe sign_whitelist.cdc
como:
import Whitelist from "../../contracts/Whitelist.cdc"
transaction {
// Configure o endereço de configuração
let address: Address
prepare(acct: AuthAccount) {
// Atribua o endereço do signatário à nossa variável de endereço
self.address = acct.address
}
execute {
// Adicione endereço ao Guestbook
Whitelist.addAddress(newAddress: self.address)
}
}
Assinando a transação da Whitelist
flow.json
Agora que temos nosso contrato em nosso diretório de projeto, vá para o seu terminal e dê cd
no diretório-base do projeto.
Digite flow init
Isso criará um arquivo flow.json
dentro do seu projeto. Isso é necessário para implantar contratos e nos fornecer erros de compilação dentro do nosso código Cadence.
Implantando nosso contrato NFT na rede de testes
Agora vamos implantar nosso contrato na rede de testes para que possamos começar a interagir com ele.
Configurando o flow.json
Dentro do seu arquivo flow.json
, faça com que o objeto contracts
fique assim:
"contracts": {
"Guestbook": "./contracts/Guestbook.cdc"
},
Isso permitirá que seu flow.json
saiba onde estão seus contratos.
Configure a conta da Flow
Antes de implantar nosso contrato, precisaremos configurar uma conta na blockchain Flow. Execute o seguinte comando para gerar um novo par de chaves pública e privada:
flow keys generate
Certifique-se de anotar os valores de saída do seu console, pois precisaremos deles nas etapas a seguir.
Em seguida, iremos à torneira da Flow (Flow Faucet) para criar um novo endereço com base em nossas chaves e financiar nossa conta com alguns tokens de teste. Conclua as etapas a seguir para criar sua conta:
- Cole sua chave pública no campo de entrada especificado
- Mantenha os Algoritmos de Assinatura e Hash definidos como padrão
- Complete o captcha
- Clique em “Create Account” (Criar conta)
Com uma geração de conta bem-sucedida, obtemos um diálogo com nosso novo endereço da Flow contendo 1.000 tokens FLOW. Agora estamos prontos para fazer a implantação, mas precisamos adicionar esta conta ao arquivo Flow.json
. Abaixo de contracts
, escreva a seguinte configuração:
"accounts": {
"emulator-account": {
"address": "f8d6e0586b0a20c7",
"key": "5112883de06b9576af62b9aafa7ead685fb7fb46c495039b1a83649d61bff97c"
},
"testnet-account": {
"address": "SEU ENDEREÇO GERADO",
"key": {
"type": "hex",
"index": 0,
"signatureAlgorithm": "ECDSA_P256",
"hashAlgorithm": "SHA3_256",
"privateKey": "SUA CHAVE PRIVADA"
}
}
},
"deployments": {
"testnet": {
"testnet-account": [
"Guestbook"
]
}
}
Cole o endereço que você copiou acima onde diz SEU ENDEREÇO GERADO
e cole sua chave privada onde diz SUA CHAVE PRIVADA
.
Implantando
Agora estamos prontos para implantar! 🚀
Acesse seu terminal e digite:
flow project deploy -- network=testnet
Devemos receber uma saída informando que o contrato foi implantado com sucesso:
Parabéns por implantar seu primeiro contrato inteligente na rede Flow!
É importante observar aqui que os contratos inteligentes da Cadence existem no armazenamento da conta que os implanta, enquanto no Solidity, o contrato inteligente existe em seu próprio endereço da blockchain.
Embora existam limites para a capacidade de armazenamento da conta, eles são relativos à quantidade de tokens FLOW reservados na conta. Você pode aprender mais sobre o armazenamento de contas no Portal do Desenvolvedor Flow (Flow Developer Portal).
No meu próximo artigo vamos construir um frontend simples para interagir com nosso contrato.
Artigo original publicado por Noah Overflow. Traduzido por Paulinho Giovannini.
Oldest comments (0)