NOVO: Helius adquire a Light Protocol
Crie um app móvel para cunhar cNFTs em menos de 5 minutos
Blog/Desenvolvimento

Crie um app móvel para cunhar cNFTs em menos de 5 minutos

Engenheira de Experiência do DesenvolvedorAnam Ansari no XAnam Ansari no LinkedIn
5 min de leitura

O que esperar

Este tutorial mostra como criar um aplicativo Android para cunhar NFTs (tokens não fungíveis). A ideia é permitir que os usuários capturem imagens facilmente e cunhem NFTs comprimidos na Solana. Para isso, usaremos a Helius Mint API. Essa API acelera a cunhagem de NFTs comprimidos e reduz o código repetitivo, economizando muito tempo e planejamento. Nosso aplicativo Android será desenvolvido em Kotlin e Jetpack Compose.

O que são NFTs comprimidos?

NFTs comprimidos (cNFTs) usam compressão de estado e árvores de Merkle simultâneas para reduzir os custos de armazenamento. NFTs comprimidos são de 2.400 a 24.000 vezes mais baratos que seus equivalentes não comprimidos, mantendo estruturas idênticas.

Pré-requisitos

Antes de começar este tutorial, você deve ter conhecimentos básicos de desenvolvimento Android com Kotlin e familiaridade com a Solana.

Ferramentas

  • Android Studio: Giraffe | Versão 2022.3.1
  • Emulador ou dispositivo móvel: será usado para testar o aplicativo. Verifique se há um aplicativo de carteira compatível com MWA instalado (recomendamos a Solfare).

Chave de API

Para usar a Helius Mint API, você precisará de uma chave de API. Veja como obtê-la:

  1. Acesse o Portal do Desenvolvedor da Helius.
  2. Crie uma conta usando sua carteira Solana ou sua conta do Google ou GitHub.
  3. Depois de fazer login, siga as instruções para gerar uma chave de API.
  4. Armazene essa chave com segurança, pois ela será usada para fazer chamadas de API ao longo deste tutorial.

Como criar o app

Etapa 1: configuração do projeto

Preparamos uma base de código inicial para este projeto. 

Para começar, siga estas etapas:

  1. Acesse o projeto inicial no GitHub.
  2. Faça um fork do repositório e clone-o em seu ambiente local.

Depois de obter o código localmente, faça o seguinte:

  1. Abra o projeto no Android Studio.
  2. Aguarde o Gradle concluir o processo de build.
  3. Execute o código.

Explore o app inicial para conhecer seus recursos. Observe o botão para conectar a carteira integrado ao app. Ele permite que você se conecte a qualquer aplicativo de carteira compatível com o Mobile Wallet Adapter (MWA). O Mobile Wallet Adapter (MWA) é uma especificação de protocolo para conectar dApps móveis a aplicativos móveis de carteira, permitindo a comunicação para transações da Solana e assinatura de mensagens. O Mobile Wallet Adapter oferece suporte a estas carteiras. Você também encontrará o botão "Tirar uma foto", que atualmente permite capturar uma imagem.

Para armazenar com segurança a chave de API da Helius na base de código, acesse o arquivo local.properties e adicione a chave de API. Esse arquivo foi criado especificamente para conter informações confidenciais e é ignorado pelo Git, garantindo a confidencialidade da sua chave de API.

api_key=<your-api-key>

Agora vamos implementar a lógica para cunhar a imagem capturada como um NFT comprimido (cNFT).

Etapa 2: lógica de cunhagem

Nosso objetivo é integrar o botão "Tirar uma foto" à funcionalidade da câmera. Essa integração permitirá que os usuários capturem imagens e as cunhem como NFTs. Fornecemos um código inicial para abrir a câmera e capturar imagens. Agora, nosso foco será criar uma função para gerenciar o processo de cunhagem.‍

Helius Mint API

Esse método cunha um NFT comprimido. Ao ser executado, ele aguardará até a confirmação da transação, o que pode levar até 60 segundos durante períodos de pico de atividade na rede. Consulte a documentação para saber mais.

Comece acessando java/com/example/hmint/MainViewModel.kt e crie a função mintCNft dentro da classe MainViewModel:

Código
@HiltViewModel
class MainViewModel @Inject constructor(
    private val walletAdapter: MobileWalletAdapter,
    private val walletConnectionUseCase: WalletConnectionUseCase,
) : ViewModel() {
    
    // ...

    fun mintCNft(imageUri: Uri, nftName: String, user: String) =
        viewModelScope.launch {
            _state.update {
                _state.value.copy(
                    isLoading = true,
                )
            }
        }

}

‍Iniciaremos uma corrotina para processar a lógica de cunhagem dentro dessa função. Primeiro, recuperaremos a chave de API e definiremos as variáveis necessárias e o requestBody. Depois, você poderá personalizar o requestBody para incluir outros atributos e dados de acordo com suas necessidades:

Código
withContext(viewModelScope.coroutineContext + Dispatchers.IO) {
    val apiKey = System.getProperty("api_key") ?: ""
    val url = URL("https://mainnet.helius-rpc.com/?api-key=$apiKey")
    val mediaType = "application/json".toMediaTypeOrNull()
    val requestBody = """
        {
            "jsonrpc": "2.0",
            "id": "helius-test",
            "method": "mintCompressedNft",
            "params": {
                "name": "$nftName",
                "symbol": "HM",
                "owner": "$user",
                "description": "This is a test cNFT minted by hMint app",
                "attributes": [
                    {
                        "trait_type": "hMint",
                        "value": "1"
                    }
                ],
                "imageUrl": "$imageUri",
                "sellerFeeBasisPoints": 6900
            }
        }
        ""${'"'}.trimIndent()
                                    
}

‍Em seguida, criaremos a solicitação e inicializaremos um OkHttpClient:

Código
val body = requestBody.toRequestBody(mediaType)
val request = Request.Builder()
    .url(url)
    .post(body)
    .addHeader("accept", "application/json")
    .addHeader("content-type", "application/json")
    .build()
val client = OkHttpClient()

‍Antes de invocar o cliente, vamos definir a resposta em uma classe de dados. Crie um novo pacote chamado data e, dentro dele, um novo arquivo chamado NFTResponse.kt para definir a estrutura da resposta recebida da chamada de API.

Código
package com.example.hmint.data

data class NftMintResponse(
    val jsonrpc: String,
    val id: String,
    val result: MintResult
)

data class MintResult(
    val signature: String,
    val minted: Boolean,
    val assetId: String
)

‍Depois, dentro da classe MainViewModel, adicione à classe de dados WalletViewState um valor para mintResponse. Atualizaremos esse valor quando recebermos uma resposta:

Código
data class WalletViewState(
    // ...
    val mintResponse: String = ""
)

‍Voltando à nossa função mintCNft, usaremos o cliente para executar a solicitação e tratar adequadamente as falhas ou respostas. Ao receber uma resposta, usaremos Gson para analisar os dados e convertê-los na classe de dados NFTMintResponse criada anteriormente. Depois, atualizaremos o valor de mintResponse de acordo com o resultado:

Código
client.newCall(request).enqueue(object : Callback {
    override fun onFailure(call: Call, e: IOException) {
        // Handle failure
        e.printStackTrace()
        Log.d(TAG, "NFT Mint Failed")
        _state.update {
            _state.value.copy(
                isLoading = false,
                mintResponse = "Mint Failed"
            )
        }
    }

    override fun onResponse(call: Call, response: Response) {
        if (response.isSuccessful) {
            val responseBody = response.body?.string() ?: ""
            val gson = Gson()
            val nft = gson.fromJson(responseBody, NftMintResponse::class.java)
            Log.d(TAG, "NFT Mint Successful: $nft")
            _state.update {
                _state.value.copy(
                    isLoading = false,
                    mintResponse = "Minted Successfully"
                )
            }

        } else {
            // Handle non-successful response
            Log.d(TAG, "NFT Mint Failed: ${response.code}")
            _state.update {
                _state.value.copy(
                    isLoading = false,
                    mintResponse = "Minted Failed"
                )
            }
        }
    }
})

‍Na nossa UI, queremos informar ao usuário o resultado da função de cunhagem. Para isso, acesse java/com/example/hmint/composables/MintButton.kt, que contém o composable com o código da UI e a lógica de captura de imagem. Dentro de MintButton, onde declaramos cameraLauncher, chamaremos nossa função mintCNft. Inclua também o código para exibir um Toast quando mintResponse for atualizado.

Código
@Composable
fun MintButton(
    mainViewModel: MainViewModel = hiltViewModel()
) {

    val cameraLauncher =
        rememberLauncherForActivityResult(ActivityResultContracts.TakePicture()) {
            // ...
            mainViewModel.mintCNft(uri, "hMint", viewState.userAddress)
        }

    
    viewState.mintResponse.let { message ->
        if(message.isNotEmpty()){
            Toast.makeText(LocalContext.current, message, Toast.LENGTH_SHORT).show()
        }
    }

    // ...
}

Etapa 3: execute o app

‍Concluímos a etapa de programação. Agora, vamos executar o aplicativo. Primeiro, conecte sua carteira. Em seguida, capture uma imagem e veja o app cunhar o NFT para você de forma simples.

Conclusão

Muito bem! Você desenvolveu com sucesso um aplicativo Android que permite aos usuários cunhar NFTs comprimidos. Graças à Helius Mint API, cunhar cNFTs nunca foi tão simples: basta uma única chamada.

O que vem a seguir?

Ainda há muito o que explorar e aprimorar neste app. Uma dessas melhorias é a integração da DAS API. A API Digital Asset Standard (DAS) é uma especificação e um sistema de código aberto que fornecem uma interface unificada para interagir com ativos digitais, incluindo tokens e NFTs. Ela oferece suporte a vários tipos de ativos, incluindo tokens fungíveis, NFTs padrão e NFTs comprimidos.  Com a API, você pode buscar todos os NFTs comprimidos cunhados e exibi-los em seu aplicativo, oferecendo aos usuários uma visão completa de seus ativos digitais.

Recursos relevantes

Para aprofundar seus conhecimentos em desenvolvimento Android com Jetpack Compose, integração com a blockchain Solana e interação com APIs, explore os seguintes recursos:

Se precisar de ajuda ou suporte, fale conosco no Discord. A base de código completa está disponível no GitHub para consulta.

‍

Assine a Helius

Acompanhe as novidades mais recentes do desenvolvimento Solana e receba atualizações quando publicarmos

Imagem ampliada