Pular para o conteúdo

Estrutura do Payload

O payload TRP segue o formato TLV (Tag-Length-Value) com prefixo fixo:

trp01 + [CAMPO][TAMANHO][VALOR] + ... + [99][04][CRC]

Cada campo é composto por:

  • Tag (2 dígitos): identificador do campo
  • Length (2 dígitos): tamanho do valor em caracteres
  • Value (N caracteres): conteúdo do campo
trp01 0148UQBJ6gU8... 0208store123 030510000 0404USDT 0508tx123456 99045D57
| | | | | | |
| | | | | | +- CRC16-CCITT
| | | | | +- Transaction ID
| | | | +- Currency
| | | +- Amount (centavos)
| | +- Merchant ID
| +- TON Wallet (48 chars)
+- Prefixo TRP v1
  1. O payload deve começar com trp01
  2. Tamanho mínimo: 15 caracteres
  3. Tamanho máximo: 512 caracteres
  4. Campos podem aparecer em qualquer ordem, exceto o CRC que é sempre o último
  5. O tamanho do campo deve ser numérico e ter exatamente 2 dígitos

O CRC16-CCITT é calculado sobre o payload completo sem o valor do CRC, mas com o header do campo 99:

crc_input = payload_sem_crc + "9904"
crc = CRC16_CCITT(crc_input) // polinômio 0x1021, inicial 0xFFFF

O resultado é um hexadecimal de 4 caracteres (uppercase).

def crc16_ccitt(data: str) -> str:
crc = 0xFFFF
for byte in data.encode('utf-8'):
crc ^= byte << 8
for _ in range(8):
if crc & 0x8000:
crc = (crc << 1) ^ 0x1021
else:
crc = crc << 1
crc &= 0xFFFF
return format(crc, '04X')
function crc16Ccitt(data: string): string {
let crc = 0xffff
for (let i = 0; i < data.length; i++) {
crc ^= data.charCodeAt(i) << 8
for (let j = 0; j < 8; j++) {
crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1
crc &= 0xffff
}
}
return crc.toString(16).toUpperCase().padStart(4, '0')
}