Pular para o conteúdo principal

Integração com contratos inteligentes na TRON

Este guia explica como receber pagamentos cripto não custodiais na TRON com os contratos inteligentes de pagamento da Volet.com e TronWeb.

Os clientes conectam as carteiras deles, aprovam as transações e pagam diretamente na sua carteira de recebimento por meio de um contrato inteligente. Os fundos não são creditados em uma conta Volet.com.

Antes de continuar, veja Integração com contratos inteligentes para uma visão geral do fluxo de pagamento.

Visão geral da integração​

  1. Conecte a carteira do cliente e confirme que ela está usando a TRON Mainnet.
  2. Configure os contratos de pagamento e a sua carteira de recebimento.
  3. Crie um pedido no backend antes de iniciar o pagamento.
  4. Chame previewPayment() para calcular o valor total do pagamento.
  5. Chame transfer() para iniciar o pagamento. Em USDT, verifique a permissão de gasto (allowance) do token e solicite a aprovação se necessário.
  6. Salve o hash da transação de pagamento (txid) no pedido.
  7. Verifique a transação no backend com dados solidificados da blockchain antes de marcar o pedido como pago.

Antes de começar​

Você vai precisar de:

  • Carteira do cliente: TronLink para pagamentos no navegador.
  • Biblioteca: TronWeb para interagir com carteiras e contratos inteligentes da TRON.
  • Carteira do lojista: um endereço de carteira da TRON que você controla para receber pagamentos.
  • Backend e banco de dados: para criar pedidos, armazenar os dados das transações e verificar os pagamentos.
  • Acesso à blockchain: um nó da TRON ou um serviço hospedado, como o TronGrid, para obter e verificar as transações.

Para conectar carteiras móveis, você também vai precisar de um Project ID do WalletConnect e de uma integração compatível com carteiras da TRON.

Redes e ativos suportados​

RedeAtivos suportados
TRON MainnetTRX, USDT (TRC-20)

TRX e USDT usam contratos processadores de pagamento diferentes.

Os valores em TRX são expressos em SUN, a menor unidade de TRX. Um TRX equivale a 1.000.000 SUN.

O USDT TRC-20 usa 6 decimais. Um USDT equivale a 1.000.000 unidades base do token.

Os exemplos de código abaixo contêm os endereços dos processadores e dos tokens da configuração da integração.

Os endereços dos contratos, os decimais dos tokens e os parâmetros das funções estão na Referência de contratos inteligentes.

Antes de usar os exemplos em produção, confirme com a Volet.com os endereços dos processadores implantados e a interface do contrato.

Etapa 1. Conecte a carteira do cliente​

Use o TronLink para conectar a carteira de navegador do cliente.

<button id="connect-tron">Connect TronLink</button>

<script>
let tronWeb;

document.getElementById('connect-tron').addEventListener('click', async () => {
if (!window.tronLink || !window.tronWeb) {
alert('Install and unlock TronLink.');
return;
}

const result = await window.tronLink.request({
method: 'tron_requestAccounts'
});

if (result?.code !== 200) {
throw new Error('Wallet connection rejected');
}

tronWeb = window.tronWeb;

document.getElementById('connect-tron').textContent =
tronWeb.defaultAddress.base58;
});
</script>

O cliente deve se conectar à TRON Mainnet.

Verifique a rede ativa antes de enviar um pagamento. Não identifique a rede apenas pela URL do endpoint RPC, porque as carteiras podem usar nós personalizados.

Seu aplicativo também deve detectar mudanças de conta e de rede na carteira e validar a conexão de novo antes de iniciar uma transação.

Etapa 2. Configure os contratos de pagamento​

Adicione ao seu aplicativo a ABI do processador de pagamentos e as funções do token.

const PROCESSOR_ABI = [
{
name: 'previewPayment',
type: 'function',
stateMutability: 'view',
inputs: [
{ name: 'amount', type: 'uint256' },
{ name: 'buyerPaysCommission', type: 'bool' },
],
outputs: [
{ name: 'commission', type: 'uint256' },
{ name: 'totalPay', type: 'uint256' },
],
},
{
name: 'transfer',
type: 'function',
stateMutability: 'payable',
inputs: [
{ name: 'seller', type: 'address' },
{ name: 'amount', type: 'uint256' },
{ name: 'buyerPaysCommission', type: 'bool' },
{ name: 'optionalCommissionWallet', type: 'address' },
],
outputs: [],
},
];

const TOKEN_ABI = [
{
name: 'balanceOf',
type: 'function',
stateMutability: 'view',
inputs: [{ name: 'account', type: 'address' }],
outputs: [{ type: 'uint256' }],
},
{
name: 'allowance',
type: 'function',
stateMutability: 'view',
inputs: [
{ name: 'owner', type: 'address' },
{ name: 'spender', type: 'address' },
],
outputs: [{ type: 'uint256' }],
},
{
name: 'approve',
type: 'function',
stateMutability: 'nonpayable',
inputs: [
{ name: 'spender', type: 'address' },
{ name: 'amount', type: 'uint256' },
],
outputs: [{ type: 'bool' }],
},
];

const TRON_PROCESSOR_TRX = 'TSK9sgBTjvZa6x2yW1bXNWqvQ57WsVUQ3W';
const TRON_PROCESSOR_USDT = 'TDuE6VueULx5oivQd4MsYr9DEhNMgXNfTm';
const TRON_USDT = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';
const TRON_ZERO = 'T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb';

const TRON_FEE_LIMIT = 500_000_000;

O processador de pagamentos oferece duas funções principais:

  • previewPayment(amount, buyerPaysCommission) calcula a taxa de processamento e o valor total que o cliente deve pagar.
  • transfer(seller, amount, buyerPaysCommission, optionalCommissionWallet) executa o pagamento e distribui os fundos de acordo com a configuração de taxas do contrato.

O parâmetro amount usa as menores unidades do ativo: SUN para TRX ou unidades base do token para USDT.

O parâmetro buyerPaysCommission define quem paga a taxa de processamento:

  • true: a taxa é somada ao pagamento do cliente.
  • false: a taxa é descontada do valor que o lojista recebe.

Use TRON_ZERO em optionalCommissionWallet se não houver carteira de comissão de parceiro.

Sempre obtenha o valor total do pagamento de previewPayment(). Não calcule a taxa de processamento manualmente.

O TRON_FEE_LIMIT do exemplo é expresso em SUN e representa um limite máximo de taxa de 500 TRX, não a taxa esperada da transação. Antes de usar em produção, estime a Energy necessária e revise o limite de taxa adequado.

As definições completas dos parâmetros estão na Referência de contratos inteligentes.

Etapa 3. Receba TRX​

Pagamentos em TRX nativo exigem uma única transação na carteira.

Use previewPayment() para calcular a quantidade exata de SUN a enviar com a transação.

async function payTrx(tronWeb, seller, humanAmount, buyerPaysCommission = true) {
if (!tronWeb.isAddress(seller)) {
throw new Error('Invalid TRON seller address');
}

const processor = tronWeb.contract(
PROCESSOR_ABI,
TRON_PROCESSOR_TRX
);

const amount = tronWeb.toSun(humanAmount).toString();

const preview = await processor.previewPayment(
amount,
buyerPaysCommission
).call();

return processor.transfer(
seller,
amount,
buyerPaysCommission,
TRON_ZERO
).send({
callValue: preview.totalPay.toString(),
feeLimit: TRON_FEE_LIMIT
});
}

O callValue da transação deve ser igual ao totalPay retornado por previewPayment().

O cliente também precisa ter TRX suficiente para cobrir os recursos da blockchain e as taxas da transação.

A função retorna o hash da transação de pagamento (txid). Salve-o no pedido existente e verifique o pagamento antes de entregar o pedido.

Etapa 4. Receba USDT​

Pagamentos em USDT TRC-20 usam um contrato de token e podem exigir uma transação de aprovação adicional.

Antes de fazer um pagamento, seu aplicativo deve:

  1. Verificar o saldo de USDT do cliente com balanceOf().
  2. Verificar a permissão de gasto do processador com allowance().
  3. Se a permissão for insuficiente, solicitar a aprovação com approve().
  4. Aguardar a confirmação da aprovação.
  5. Chamar transfer() para executar o pagamento.
async function payTronUsdt(tronWeb, seller, amountBaseUnits, buyerPaysCommission = true) {
if (!tronWeb.isAddress(seller)) {
throw new Error('Invalid TRON seller address');
}

if (!/^\d+$/.test(amountBaseUnits) || BigInt(amountBaseUnits) <= 0n) {
throw new Error('USDT amount must be a positive integer in base units');
}

const processor = tronWeb.contract(
PROCESSOR_ABI,
TRON_PROCESSOR_USDT
);

const token = tronWeb.contract(
TOKEN_ABI,
TRON_USDT
);

const owner = tronWeb.defaultAddress.base58;

const preview = await processor.previewPayment(
amountBaseUnits,
buyerPaysCommission
).call();

const total = BigInt(preview.totalPay.toString());

const balance = BigInt(
(await token.balanceOf(owner).call()).toString()
);

if (balance < total) {
throw new Error('Insufficient USDT');
}

const allowance = BigInt(
(await token.allowance(owner, TRON_PROCESSOR_USDT).call()).toString()
);

if (allowance < total) {
const approvalTxid = await token.approve(
TRON_PROCESSOR_USDT,
total.toString()
).send({ feeLimit: TRON_FEE_LIMIT });

return {
state: 'approval_pending',
approvalTxid
};
}

const paymentTxid = await processor.transfer(
seller,
amountBaseUnits,
buyerPaysCommission,
TRON_ZERO
).send({ feeLimit: TRON_FEE_LIMIT });

return {
state: 'payment_pending',
paymentTxid
};
}

Requisitos de aprovação de USDT​

Dependendo da permissão existente, um pagamento em USDT pode exigir:

Permissão existenteTransações necessárias
SuficienteSomente o pagamento
InsuficienteAprovação + pagamento

Se for necessária uma aprovação, a função retorna approval_pending com o hash da transação de aprovação.

Aguarde a confirmação da aprovação antes de chamar a função de pagamento de novo. Quando a permissão for suficiente, a função envia o pagamento e retorna payment_pending com o hash da transação de pagamento.

Importante:

  • Uma transação approve() não é um pagamento.
  • O cliente precisa de TRX suficiente para cobrir os custos de Energy e Bandwidth, mesmo ao pagar em USDT.
  • Os valores em USDT devem ser expressos como inteiros em unidades base do token. Evite cálculos de ponto flutuante como Math.round(parseFloat(amount) * 1e6).
  • Acompanhe as transações de aprovação separadamente da transação de pagamento final.

Etapa 5. Salve a transação de pagamento​

Seu backend deve criar um pedido antes de o cliente enviar um pagamento.

Cada pedido deve conter os valores esperados de:

  • ID do pedido
  • Rede blockchain
  • Ativo e valor
  • Carteira de recebimento do lojista (seller)
  • Contrato processador de pagamentos aprovado
  • Carteira do comprador, se a sua página de pagamento exigir
  • Configuração da taxa de processamento (buyerPaysCommission)

Depois que o cliente enviar o pagamento:

  1. Obtenha o hash da transação de pagamento (txid) retornado pela carteira.
  2. Envie o hash para o backend.
  3. Armazene-o com o ID do pedido e a rede blockchain.
  4. Inicie a verificação do pagamento no servidor.

Cada transação de pagamento deve estar associada a no máximo um pedido. Garanta isso com uma restrição única (network, txid) no banco de dados.

A função transfer() do contrato inteligente não aceita um ID de pedido. A relação entre o pedido e a transação de pagamento dele deve ser mantida pelo seu aplicativo.

Se um cliente tentar pagar de novo, mantenha as tentativas de pagamento separadas em vez de sobrescrever registros de transações que ainda podem estar pendentes.

Etapa 6. Verifique o pagamento​

A verificação do pagamento é obrigatória antes de concluir um pedido.

Um hash de transação retornado indica apenas que uma transação foi enviada. Ele não prova que o lojista recebeu o pagamento correto.

Seu backend deve, de forma independente:

  1. Obter a transação e o recibo de execução da blockchain.
  2. Confirmar a execução bem-sucedida com um recibo solidificado da TRON.
  3. Verificar se a transação usou o processador de pagamentos esperado.
  4. Comparar o ativo, a carteira do lojista, o valor e a chamada ao contrato com o pedido.
  5. Confirmar que o lojista recebeu os fundos esperados.
  6. Garantir que a transação ainda não foi usada para outro pedido.
  7. Marcar o pedido como pago e entregá-lo uma única vez.

Para obter dados solidificados da transação, use o endpoint do SolidityNode da TRON:

POST https://api.trongrid.io/walletsolidity/gettransactioninfobyid

Verifique se receipt.result === 'SUCCESS' e depois confira o corpo da transação e os dados reais do pagamento com o pedido.

Um recibo bem-sucedido não basta. Uma transação pode ser executada com sucesso sem pagar o lojista certo ou o valor certo.

Se o serviço de blockchain estiver temporariamente indisponível ou a transação ainda não estiver solidificada, mantenha o pedido pendente e tente a verificação de novo.

Siga Verificação de pagamentos e acompanhamento de pedidos para a implementação completa no backend, os requisitos de confirmação na TRON e o checklist de produção.

Você também pode consultar TRON confirmation semantics.

Opcional: suporte a carteiras móveis​

Para oferecer suporte a carteiras móveis via WalletConnect, use uma integração compatível com carteiras da TRON, como @tronweb3/walletconnect-tron, junto com o TronWeb.

Isso exige um Project ID do WalletConnect e uma integração capaz de criar transações da TRON, solicitar assinaturas às carteiras móveis e transmitir as transações assinadas.

O exemplo para navegador descrito abaixo suporta o TronLink. Ele não implementa o fluxo de carteiras móveis com WalletConnect.

Exemplo de integração​

O exemplo example-tron.html mostra:

  • A conexão do TronLink.
  • O cálculo dos valores de pagamento com previewPayment().
  • O envio de pagamentos em TRX e USDT TRC-20.
  • A exibição dos hashes das transações e o acompanhamento do status delas.

Você pode abrir o exemplo no navegador ou baixar o arquivo HTML para estudar e adaptar o código:

Extensões de carteira do navegador, como o TronLink, podem não funcionar corretamente com páginas abertas diretamente do disco (file://). Sirva o arquivo baixado por um servidor web local. Por exemplo, execute npx serve na pasta do arquivo e abra a URL de localhost exibida.

Experimente o exemplo​

  1. Abra o exemplo ao vivo ou sirva o arquivo baixado localmente em um navegador com o TronLink instalado.
  2. Selecione Mainnet no TronLink e depois clique em Connect TronLink. A demo avisa se a carteira estiver conectada a outra rede.
  3. Selecione o método de pagamento: TRX ou USDT TRC-20.
  4. Informe a carteira de recebimento da TRON em Seller address.
  5. Informe o valor do pagamento e escolha quem paga a taxa de processamento.
  6. Clique em Preview para ver a taxa de processamento e o valor total do pagamento. Depois clique em Pay e confirme a transação no TronLink. Pagamentos em USDT podem exigir antes uma aprovação separada do token.
  7. O pedido e o hash da transação aparecem na tabela Orders. A demo verifica o status da transação por até 5 minutos.

Antes de pagar:

  • Use duas carteiras diferentes. O endereço do vendedor deve ser diferente da carteira pagadora. Caso contrário, o contrato rejeita o pagamento com SellerIsBuyer.
  • As transações usam fundos reais. O exemplo vem preenchido com 1 TRX. Confira o valor do pagamento, a taxa de processamento e o custo dos recursos da rede TRON (Energy e Bandwidth) antes de confirmar.

Limitações da demo: este exemplo armazena o histórico de transações no localStorage do navegador e não é uma página de pagamento de produção. Ele verifica o recibo mais recente da transação com getTransactionInfo(), o que não garante a solidificação na TRON. A janela de acompanhamento de 5 minutos é apenas um limite da demo, não um prazo de confirmação do pagamento. Implemente o processo completo de verificação de pagamentos antes de aceitar pedidos de clientes.