
Solana Frames: cunhando um cNFT no Farcaster
Sobre o que é este artigo?
As redes sociais descentralizadas representam uma mudança significativa rumo a mais privacidade e controle dos usuários sobre seus dados online. Diferentemente das plataformas de redes sociais tradicionais, as redes descentralizadas permitem que as pessoas gerenciem diretamente seus grafos sociais e suas identidades digitais. Plataformas como o Farcaster estão na vanguarda dessa transformação, criando redes resistentes à censura que promovem uma comunicação aberta e interoperável entre diversas plataformas. Uma inovação importante do Farcaster é a introdução dos Frames, que transformam publicações comuns em aplicativos completos para enriquecer as experiências sociais online.
Este artigo abordará o Farcaster e seu recente suporte à Solana. Veremos o que é o Farcaster, o que são Frames e como verificar um endereço Solana. Em seguida, apresentaremos um breve tutorial para criar um Frame que cunha um cNFT no endereço Solana verificado de um usuário usando a Helius Mint API. Para acompanhar o tutorial, pressupomos experiência prévia com TypeScript e Next.js.
O que é o Farcaster?
O Farcaster é uma rede social suficientemente descentralizada que utiliza a rede Ethereum. Ele oferece uma plataforma pública semelhante a redes sociais populares, como Twitter e Reddit, na qual os usuários podem criar perfis, compartilhar publicações, conhecidas como casts, e seguir outros usuários. O diferencial do Farcaster é a ênfase na propriedade e na portabilidade para o usuário: os usuários são donos de suas contas e de suas relações com outras pessoas. Eles podem migrar entre diferentes aplicativos sem perder sua identidade digital nem seu grafo social.
O que são Frames?
Os Frames permitem que os desenvolvedores transformem qualquer cast em um aplicativo interativo. Ao ampliar o padrão OpenGraph, eles transformam incorporações estáticas em experiências dinâmicas e interativas. Isso permite criar recursos como enquetes, feeds ao vivo ou galerias interativas em qualquer cliente do Farcaster, incluindo o Warpcaster. Em essência, um Frame é um conjunto de tags <meta> retornadas com o <head> de uma página HTML. Os aplicativos do Farcaster renderizam a página como um Frame quando ela contém todas as propriedades obrigatórias de um Frame. A Especificação de Frames descreve essas propriedades obrigatórias. Por exemplo, um Frame inicial deve:
- Retornar um Frame válido na seção HTML
<head> - Retornar um HTML
<body>válido caso o usuário abra o Frame em um navegador - Não incluir conteúdo dinâmico no Frame inicial, pois os clientes do Farcaster o armazenam em cache
- Não incluir uma tag
fc:frame:state
Como verificar um endereço Solana no Farcaster
O Farcaster adicionou recentemente suporte a endereços Solana. Isso significa que os desenvolvedores podem criar Frames que interagem com a carteira Solana de um usuário. Em menos de 24 horas após o lançamento do suporte, mais de 9.328 FIDs únicos do Farcaster verificaram um endereço Solana.
Os usuários podem verificar seu endereço Solana da seguinte forma:
- Acessar Configurações
- Clicar em Endereços verificados e depois no botão “Verificar um endereço”
- Conectar a carteira Solana e assinar uma mensagem para comprovar a propriedade
Observe que, no momento, a única carteira compatível é a Phantom.
Tutorial: como criar um Frame que cunha um cNFT
Neste artigo, criaremos um Frame que permite aos usuários com um endereço Solana verificado cunhar um NFT compactado (cNFT). Inicializaremos o projeto usando o frames.js, um template do Next.js para criar e depurar Frames. Usaremos o OnchainKit da Coinbase, especificamente o Frame Kit, para buscar as informações de um usuário do Farcaster quando ele interagir com o Frame. Depois, enviaremos esses dados à Helius Mint API para cunhar o seguinte cNFT na carteira Solana do usuário:
Como configurar nosso Frame
Criar um Frame com o frame.js é tão simples quanto clonar o template inicial. Basta executar o comando abaixo, substituindo <name> pelo nome da nova pasta na qual você deseja clonar o template:
npx degit github:framesjs/frames.js/examples/framesjs-starter#main <name>Decidi nomear meu diretório como helius-frame, então substituí <name> por <helius-frame>. Em seguida, acesse o novo diretório (por exemplo, cd helius-frame) e instale as dependências necessárias com o comando yarn install. Quando o download terminar, execute yarn dev para iniciar o servidor de desenvolvimento. Acesse http://localhost:3000 no navegador para ver o seguinte:
Ao clicar no hiperlink Debug, você será direcionado para http://localhost:3000/debug:
Isso é útil porque podemos testar nosso Frame localmente sem implantá-lo. Por exemplo, podemos fazer login para testar botões, simular outros usuários e criar um estado fictício do hub. O Warpcaster também oferece uma excelente ferramenta de Validação de Frames. Daqui em diante, usaremos a ferramenta de Validação de Frames nos testes por mera preferência pessoal.
Em seguida, execute yarn install para instalar as dependências relevantes do template. Também precisaremos executar yarn install @coinbase/onchainkit para instalar o OnchainKit.
Vamos reorganizar as pastas do projeto da seguinte forma:
- Exclua a pasta examples. Embora os exemplos ofereçam informações valiosas sobre a criação de Frames, eles são desnecessários para o que queremos fazer. Remover essa pasta reduz o tamanho desnecessário do projeto. No entanto, recomendo fortemente analisá-los para conhecer maneiras alternativas de criar Frames comuns
- Crie uma pasta api no diretório app. Esta etapa segue as convenções do Next.js para rotas de API, oferecendo uma distinção clara entre o frontend e o backend do nosso aplicativo. Depois, mova a pasta frames, junto com seu conteúdo, route.ts, para a nova pasta api.
- Crie uma pasta utils no diretório app. Nessa nova pasta, crie um arquivo mint.ts. É nele que colocaremos nossa lógica de cunhagem do cNFT
Agora podemos finalmente começar a criar nosso Frame!
Como editar nosso Frame
layout.tsx
Começaremos pelo arquivo layout.tsx. Exclua todo o conteúdo dele e substitua-o pelo código a seguir:
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
{children}
);
}O componente RootLayout adota uma abordagem minimalista para envolver todo o aplicativo em uma estrutura de layout consistente. Ele é flexível e foi projetado para ser reutilizável. A partir desse layout minimalista, os desenvolvedores podem usar o arquivo como template para criar e personalizar seus próprios Frames conforme necessário.
Observe que alterar o arquivo layout.tsx causará problemas ao usar o depurador localmente. Editar o layout.tsx não é obrigatório. No entanto, fazemos isso para introduzir os metadados do aplicativo em page.tsx. Como alternativa, você poderia inserir os metadados neste arquivo.
page.tsx
Exclua o conteúdo de page.tsx e substitua-o pelo seguinte:
import type { Metadata } from "next";
import { getFrameMetadata } from "@coinbase/onchainkit";
const baseURL = "https://helius-frame.vercel.app/";
const frameMetadata = getFrameMetadata({
image: {
src: `${baseURL}/default.jpg`,
aspectRatio: "1:1",
},
buttons: [
{
label: "Click to mint a cNFT on Solana!",
action: "post",
},
],
postUrl: `${baseURL}api/frames`,
});
export const metadata: Metadata = {
title: "Mint a cNFT on Solana",
description: "Mint a cNFT to your verified Solana address using the Helius Mint API",
openGraph: {
title: "Mint a cNFT on Solana",
description: "Mint a cNFT to your verified Solana address using the Helius Mint API",
images: ["https://helius-frame.vercel.app/default.jpg"],
},
other: {
...frameMetadata,
},
};
export default function Page() {
return (
Mint a cNFT on Farcaster using the Helius Mint API
Built by 0xIchigo
GitHub Repo
);
}O código acima configura nosso Frame inicial, que ficará disponível em uma URL em um servidor web. No meu caso, o Frame inicial está hospedado na Vercel, em https://helius-frame.vercel.app/. Veremos como fazer a implantação com a Vercel mais adiante neste tutorial.
Primeiro, importamos o tipo Metadata do Next.js para tipar a exportação metadata neste arquivo. Também importamos getFrameMetadata de @coinbase/onchainkit. Em seguida, definimos a URL base do aplicativo para evitar código repetitivo.
Depois, chamamos getFrameMetadata para configurar os metadados do nosso Frame inicial. Esses metadados incluem:
- Uma imagem, ou seja, src, que serve como elemento visual do Frame, com proporção de 1:1
- Um botão com o texto “Clique para cunhar um cNFT na Solana!” que, quando clicado, aciona uma solicitação POST para o
postUrlespecificado, ou seja,${baseURL}api/frames. Essa ação inicia o processo de cunhagem
Em seguida, exportamos um objeto metadata que inclui o título e a descrição da página, os metadados do OpenGraph, ou seja, openGraph, e o frameMetadata definido anteriormente, expandido na propriedade other.
Por fim, page define e exporta o componente padrão da página. Retornamos um h1 básico que instrui o usuário a cunhar um cNFT. Isso ocorre porque o Farcaster exige que retornemos algum HTML. A interação principal é gerenciada por Frames, e não pelo acesso direto ao próprio site. No entanto, se um usuário abrir o site, ainda será necessário exibir algum conteúdo.
mint.ts
Cole o código a seguir em mint.ts:
const url = `Get a URL at dev.helius.xyz`;
export const mintCompressedNFT = async (address: string) => {
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: "frames-sol-mint",
method: "mintCompressedNft",
params: {
name: "Solana Soldier",
symbol: "HELIUS",
owner: address,
description: "A decentralized warrior backed by Solana's most loved RPC Nodes, APIs, Webhooks, and Developer Tooling",
attributes: [
{
trait_type: "RPCs",
value: "Fast",
},
{
trait_type: "Company",
value: "Helius"
},
],
imageUrl: "https://shdw-drive.genesysgo.net/HmvVwYAy7cxWECLbu2cjWBSHysVoriTqgdugyePVg3rY/cnftmint.jpg",
externalUrl: "https://www.helius.dev/",
sellerFeeBasisPoints: 6900,
},
}),
});
const data = await response.json();
console.log(`data: ${JSON.stringify(data, null, 2)}`);
if (!response.ok) {
throw new Error(`The response was not okay - ${response.status}`);
}
if (!data.result || !data.result.assetId) {
throw new Error(`The response did not include the expected data.result.assetId field`);
}
return data.result;
};A função utilitária mintCompressedNFT é essencial para nosso aplicativo, pois cunha um cNFT predefinido em um endereço específico. Usamos a Helius Mint API para criar uma função simples, reutilizável e assíncrona que encapsula o processo de cunhagem do cNFT. Precisamos solicitar nossa URL de General RPC da Helius, definida como url. Se você ainda não tiver uma, acesse seu painel da Helius para gerar gratuitamente uma URL de RPC e usá-la em url.
Observe que meu repositório usa minha URL de SecureRPC. Tenha cuidado para não expor sua chave de API e considere executar um proxy. Quanto à solicitação em si, você pode encontrar uma descrição completa do schema aqui.
Também vale observar que já fiz upload da imagem do cNFT para o ShdwDrive, pois, no momento em que este artigo foi escrito, o Farcaster ainda não havia adicionado suporte completo a transações. A Helius Mint API gerencia o upload de metadados off-chain para o Arweave, desde que um signatário seja fornecido.
A função também inclui um tratamento robusto de erros para garantir que qualquer problema durante o processo de cunhagem seja detectado e informado. Ela também registra os dados da resposta para fins de depuração.
route.ts
Em api/frames/route.ts, cole o seguinte código:
import { NextRequest, NextResponse} from "next/server";
import { getFrameMessage, getFrameHtmlResponse } from "@coinbase/onchainkit/frame";
import { mintCompressedNFT } from "../../utils/mint";
const baseURL = "https://helius-frame.vercel.app/";
export async function POST(req: NextRequest): Promise {
const body = await req.json();
// Validate the frame message and extract the user ID
const { isValid, message } = await getFrameMessage(body, {
neynarApiKey: "NEYNAR_ONCHAIN_KIT",
});
console.log(JSON.stringify(message, null, 2));
// Make sure they're following us before they can mint the cNFT
if (isValid && !message.following) {
return new NextResponse(getFrameHtmlResponse({
image: {
src: `${baseURL}/error.jpg`,
aspectRatio: "1:1",
},
buttons: [
{
label: "You need to be following to mint! Click to retry",
action: "post",
},
],
postUrl: `${baseURL}api/frames`,
}));
// Make sure they have a verified Solana address
} else if (isValid && message.interactor.verified_addresses.sol_addresses) {
const solanaAddresses = message.interactor.verified_addresses.sol_addresses;
console.log(`SOLANA ADDRESSES: ${solanaAddresses}`);
if (solanaAddresses.length !== 0) {
try {
console.log(`MINTING to ${solanaAddresses[0]}`);
// We take the first address address, in case there's more than one
const mintResult = await mintCompressedNFT(solanaAddresses[0]!);
return new NextResponse(getFrameHtmlResponse({
image: {
src: `${baseURL}/success.jpg`,
aspectRatio: "1:1",
},
buttons: [
{
label: "Success! View your cNFT on XRAY",
action: "link",
target: `https://xray.helius.xyz/token/${mintResult.assetId}?network=mainnet`
},
],
}));
} catch (e: any) {
console.log(`Minting failed: ${e}`);
return new NextResponse(getFrameHtmlResponse({
image: {
src: `${baseURL}/error.jpg`,
aspectRatio: "1:1",
},
buttons: [
{
label: "Minting failed. Click to retry",
action: "post",
},
],
postUrl: `${baseURL}api/frames`,
}));
}
} else {
console.log(`No Solana address found`);
return new NextResponse(getFrameHtmlResponse({
image: {
src: `${baseURL}/error.jpg`,
aspectRatio: "1:1",
},
buttons: [
{
label: "No Solana address found. Click to retry",
action: "post",
},
],
postUrl: `${baseURL}api/frames`
}));
}
} else {
return new NextResponse(getFrameHtmlResponse({
image: {
src: `${baseURL}/error.jpg`,
aspectRatio: "1:1",
},
buttons: [
{
label: "Invalid frame message. Click to retry",
action: "post",
},
],
postUrl: `${baseURL}api/frames`,
}));
}
}Este arquivo é uma rota de API do Next.js que processa todas as solicitações POST do nosso Frame. O arquivo começa importando NextRequest e NextResponse de next/server para processar solicitações recebidas e enviar respostas. Também importamos getFrameMessage e getFrameHtmlResponse de @coinbase/onchainkit/frame para validar mensagens de Frames e gerar respostas HTML para interações com o Frame. Também importamos nossa função utilitária mintCompressedNFT.
baseURL é definido para reduzir a repetição de código. Ele é usado para construir caminhos de recursos e endpoints de API.
O arquivo exporta a função POST, que analisa o corpo da solicitação recebida para extrair a mensagem do Frame. Usamos getFrameMessage para verificar se a interação recebida do Frame e o payload da mensagem são válidos. Para isso, passamos o corpo da solicitação como JSON e a chave de API padrão da Neynar, ou seja, “NEYNAR_ONCHAIN_KIT”. A Neynar é uma plataforma para desenvolvedores que busca simplificar o desenvolvimento no Farcaster. getFrameMessage retorna uma Promise que é resolvida como um FrameValidationResponse. Sua definição é:
export type FrameValidationResponse =
| { isValid: true; message: FrameValidationData }
| { isValid: false; message: undefined };Portanto, se a interação com o Frame for válida, ela retornará a mensagem do tipo FrameValidationData. Sua definição é:
export interface FrameValidationData {
button: number; // Number of the button clicked
following: boolean; // Indicates if the viewer clicking the frame follows the cast author
input: string; // Text input from the viewer typing in the frame
interactor: {
fid: number; // Viewer Farcaster ID
custody_address: string; // Viewer custody address
verified_accounts: string[]; // Viewer account addresses
verified_addresses: {
eth_addresses: string[] | null;
sol_addresses: string[] | null;
};
};
liked: boolean; // Indicates if the viewer clicking the frame liked the cast
raw: NeynarFrameValidationInternalModel;
recasted: boolean; // Indicates if the viewer clicking the frame recasted the cast
valid: boolean; // Indicates if the frame is valid
}Isso é extremamente valioso, pois inclui dados relevantes, como o ID do usuário no Farcaster, se ele tem endereços Ethereum ou Solana verificados e se curtiu o cast. Neste tutorial, queremos verificar se o usuário que está tentando fazer a cunhagem segue meu perfil. Se seguir, permitiremos que ele cunhe o cNFT. Também queremos garantir que ele tenha um endereço Solana verificado no qual possamos cunhar o cNFT.
Primeiro, verificamos se a interação é válida e se o usuário segue minha conta. Caso contrário, ele recebe uma mensagem de erro e um botão para tentar novamente. Depois, verificamos se o usuário tem um endereço Solana verificado. Se houver um ou mais endereços, prosseguimos com o processo de cunhagem. Pegamos o primeiro endereço Solana verificado e o passamos para mintCompressedNFT. Se a operação for bem-sucedida, retornamos uma imagem de sucesso e um link para visualizar o cNFT no Orb. Em caso de falha, registramos o erro e respondemos com uma mensagem que solicita ao usuário que tente novamente. Se nenhum endereço Solana verificado for encontrado, responderemos com uma mensagem de erro indicando a ausência de um endereço Solana verificado e solicitaremos que o usuário tente novamente. Por fim, se a mensagem do Frame for inválida, responderemos com uma mensagem de erro sobre o Frame inválido e solicitaremos que o usuário tente novamente.
O código usa getFrameHtmlResponse para gerar respostas HTML adaptadas aos resultados específicos do processo de cunhagem ou das verificações de validação. Isso inclui definir as imagens, as proporções e os botões das respostas para interações específicas do usuário.
Envio para produção
Com o código pronto, crie um novo repositório no GitHub e envie o código para ele. Execute os seguintes comandos na linha de comando para enviar o código ao GitHub:
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/<username>/<new repo name>.git
git branch -M main
git push -u origin mainDepois de enviar o código ao GitHub, a próxima etapa é implantar o aplicativo. A Vercel oferece uma integração perfeita com o GitHub, simplificando todo o processo de implantação. Por isso, vamos usá-la. Para continuar:
- Entre na sua conta pelo site da Vercel. Se não tiver uma conta, você precisará criar uma. A plataforma oferece um plano Hobby generoso, ou seja, gratuito, que será suficiente para nossos objetivos
- Depois de entrar, acesse o painel e clique no botão Novo projeto. A Vercel solicitará que você importe um projeto do GitHub. Selecione o repositório que acabou de criar na etapa anterior
- A Vercel detectará automaticamente o framework usado e sugerirá configurações de build. A Vercel foi criada pelos criadores do Next.js e oferece suporte de primeira classe, portanto não precisamos nos preocupar muito com uma configuração trabalhosa
- Depois de definir as configurações do projeto, clique no botão Implantar. A Vercel iniciará automaticamente o processo de implantação, fazendo o build e implantando o projeto em uma URL exclusiva da Vercel.
- Após a implantação, a Vercel fornecerá essa URL exclusiva para você acessar o aplicativo em produção. Meu projeto foi publicado em https://helius-frame.vercel.app/: o nome do repositório no GitHub seguido por .vercel.app. A Vercel também permite configurar domínios personalizados nas configurações do projeto
Pronto! Ao seguir essas etapas, enviamos nosso Frame do Farcaster para o GitHub e o hospedamos na Vercel. Você pode testar a funcionalidade do Frame usando as ferramentas mencionadas anteriormente, como o validador de Frames. Agora só falta criar um cast com a URL do Frame!
Conclusão
A convergência entre blockchains e redes sociais representa um avanço significativo na forma como concebemos os espaços digitais e interagimos neles. A popularidade do Farcaster e dos Frames transforma o que antes eram publicações estáticas nas plataformas tradicionais de redes sociais em experiências interativas. Este artigo explora o Farcaster e os Frames. O tutorial apresentado é uma introdução ao uso do recente suporte do Farcaster à Solana para cunhar cNFTs para usuários com o clique de um único botão. Seja você um desenvolvedor interessado em criar no Farcaster ou alguém que queira navegar pelo feed de uma rede social de uma maneira nova e empolgante, as possibilidades são infinitas.
Se você leu até aqui, valeu, anon! Se quiser entrar no Farcaster, use o seguinte link de convite!
Insira seu endereço de e-mail abaixo para nunca perder uma atualização sobre as novidades da Solana. Quer se aprofundar? Explore os artigos mais recentes no blog da Helius e continue hoje mesmo sua jornada pela Solana.
Recursos adicionais
Artigos relacionados
Assine a Helius
Acompanhe as novidades mais recentes do desenvolvimento Solana e receba atualizações quando publicarmos


