DOCS/
App
Sweetly Developer Ecosystem

Documentação para Desenvolvedores

Construa bots interativos para chat, automatize recompensas de transmissão, integre eventos em tempo real via Socket.IO e processe pagamentos onchain com USDC na rede Base.

Blockchain

Base L2 (8453)

Tempo Real

Socket.IO v4

Moeda de Liquidação

USDC (6 Decimais)

Protocolo de Vídeo

HLS c/ DVR

Visão Geral

Introdução à Sweetly Developer API & Bot Platform

O Sweetly é uma plataforma de live streaming de alta performance que combina a fluidez da Web2 (latência ultrabaixa em vídeo e chat) com a soberania financeira da Web3 (microtransações transparentes, assinaturas e governança com contratos inteligentes na Base).

Chat & Interatividade

Conexões Socket.IO de baixa latência para mensagens, moderação com timeout e ban, além de slash commands integrados.

Spotlight & Votação

Sistema comunitário de votos para rankear streamers no Spotlight em tempo real, permitindo que bots engajem a audiência.

Liquidação Onchain

Gorjetas e assinaturas em USDC na Base com verificação criptográfica de recibos e renovações automáticas via Keepers.

Arquitetura Híbrida Web3

Para garantir escalabilidade sem sacrificar a descentralização, a plataforma opera em duas camadas complementares:

1. Camada de Aplicação em Tempo Real (Offchain / Edge):

Node.js + Socket.IO Cluster com persistência e broadcast de eventos em microssegundos. Vídeo servido por Edge HLS com buffers DVR adaptativos.

2. Camada de Liquidação e Confiança (Onchain / Base L2):

Smart Contracts no Base Mainnet. Gorjetas em USDC nativo transferidas direto carteira-a-carteira, com verificação de recibo via Viem e automação de assinaturas recorrentes com o SubscriptionManager.

Autenticação e Sessões

A API do Sweetly suporta três mecanismos dependendo do tipo de cliente:

A. Session Cookie (Better-Auth)

Utilizado para rotas do streamer e do usuário no navegador. O cookie HTTP-only better-auth.session_token valida a identidade de forma segura contra CSRF.

B. Bearer Secret (Automações e Keepers)

Endpoints de manutenção e orquestração (como POST /api/keeper) requerem o cabeçalho Authorization: Bearer <CRON_SECRET>.

C. Verificação Criptográfica Onchain

Gorjetas e votos não dependem de segredos estáticos; a autenticidade é validada pelo hash da transação emitido na blockchain Base verificado pelo nó RPC.

Guia Rápido

Crie seu primeiro Bot em 5 Minutos

Conecte um bot ao chat do Sweetly para responder comandos da comunidade, registrar gorjetas onchain e moderar a live automaticamente. Escolha sua linguagem preferida abaixo:

PythonExemplo Completo com python-socketio

Instale as dependências: pip install "python-socketio[client]" requests

sweetly_bot.py
python
1"""
2Sweetly Bot - Python (5 minutos)
3Biblioteca: python-socketio e requests
4Instalação: pip install "python-socketio[client]" requests
5"""
6import socketio
7import time
8
9sio = socketio.Client(reconnection=True, reconnection_delay=1, reconnection_delay_max=5)
10
11CHANNEL_ID = "channel-uuid-aqui"
12SWEETLY_WS = "https://sweetly.live" # Ou http://localhost:1234 em desenvolvimento
13
14@sio.event
15def connect():
16 print("⚡ [Sweetly Bot] Conectado ao cluster Socket.IO!")
17 # Ingressa na sala de chat do canal
18 sio.emit("channel:join", {"channelId": CHANNEL_ID})
19 print(f"📡 Ingressou no canal: {CHANNEL_ID}")
20
21@sio.on("message:new")
22def on_message(message):
23 sender = message.get("username", "Anon")
24 content = message.get("content", "").strip()
25 user_id = message.get("userId")
26
27 print(f"💬 [{sender}]: {content}")
28
29 # Ignora mensagens enviadas pelo próprio sistema/bot
30 if user_id == "system" or sender == "SweetlyBot":
31 return
32
33 # Comandos interativos de chat
34 if content == "!ping":
35 send_chat("🏓 Pong! Bot ativo e operando com baixa latência.")
36
37 elif content == "!votar":
38 send_chat("⭐ Votos ajudam o streamer no ranking Spotlight! Clique em 'Votar' no topo da live.")
39
40 elif content == "!regras":
41 send_chat("📜 Regras: Sem spam, respeite os membros e interaja com respeito!")
42
43 elif content.startswith("!ajuda"):
44 send_chat("🤖 Comandos disponíveis: !ping, !votar, !regras, !stats")
45
46@sio.on("tip:new")
47def on_tip(tip_data):
48 # Evento disparado quando uma gorjeta onchain em USDC é confirmada na Base
49 amount = tip_data.get("amountUsd", "0.00")
50 donor = tip_data.get("donorAddress", "0x...")[:8]
51 memo = tip_data.get("message", "")
52 send_chat(f"🎉 GORJETA ONCHAIN! {donor}... enviou {amount} USDC! Mensagem: {memo}")
53
54@sio.on("vote:cast")
55def on_vote(vote_data):
56 user = vote_data.get("user", "Fã")
57 amount = vote_data.get("amount", 1)
58 send_chat(f"⭐ {user} somou +{amount} votos para o canal no ranking!")
59
60def send_chat(text: str):
61 sio.emit("message:send", {
62 "channelId": CHANNEL_ID,
63 "content": text
64 })
65
66if __name__ == "__main__":
67 try:
68 sio.connect(SWEETLY_WS, transports=["websocket"])
69 sio.wait()
70 except KeyboardInterrupt:
71 sio.disconnect()
72 print("Bot desconectado.")

TypeScriptExemplo Completo com socket.io-client

Instale a biblioteca oficial: npm install socket.io-client

bot.ts
typescript
1/**
2 * Sweetly Bot - TypeScript / Node.js (5 minutos)
3 * Instalação: npm install socket.io-client
4 */
5import { io, Socket } from "socket.io-client";
6
7interface ChatMessage {
8 readonly id: string;
9 readonly channelId: string;
10 readonly userId: string;
11 readonly username: string;
12 readonly content: string;
13 readonly isSystem: boolean;
14 readonly createdAt: string;
15}
16
17interface TipEvent {
18 readonly id: string;
19 readonly donorAddress: string;
20 readonly amountUsd: number;
21 readonly message?: string;
22 readonly txHash: string;
23}
24
25const SWEETLY_HOST = process.env.SWEETLY_HOST ?? "https://sweetly.live";
26const CHANNEL_ID = process.env.CHANNEL_ID ?? "seu-channel-uuid-aqui";
27
28// Inicializa a conexão com transporte puro WebSocket para latência mínima
29const socket: Socket = io(SWEETLY_HOST, {
30 transports: ["websocket"],
31 reconnection: true,
32 reconnectionAttempts: 15,
33 reconnectionDelay: 1000,
34 reconnectionDelayMax: 5000,
35});
36
37socket.on("connect", () => {
38 console.log("⚡ [Sweetly Bot] Conexão estabelecida:", socket.id);
39
40 // Ingressa no canal especificado
41 socket.emit("channel:join", { channelId: CHANNEL_ID }, () => {
42 console.log(`📡 Bot conectado e ouvindo a sala: ${CHANNEL_ID}`);
43 sendMessage("🤖 SweetlyBot v1.0 online e monitorando o chat!");
44 });
45});
46
47// Listener de novas mensagens no chat
48socket.on("message:new", (msg: ChatMessage) => {
49 if (msg.isSystem || msg.username === "SweetlyBot") return;
50
51 const content = msg.content.trim();
52 console.log(`[${msg.username}]: ${content}`);
53
54 if (content === "!ping") {
55 sendMessage(`🏓 Pong! Latência estimada: ${socket.io.engine?.pingInterval}ms`);
56 } else if (content === "!votar") {
57 sendMessage("⭐ Fortaleça o criador votando no ranking Spotlight pelo botão Votar!");
58 } else if (content === "!ajuda") {
59 sendMessage("📖 Comandos: !ping, !votar, !stats, !contrato");
60 } else if (content === "!contrato") {
61 sendMessage("⛓️ Assinaturas via USDC na rede Base: 5 USDC / 30 dias!");
62 }
63});
64
65// Listener de Gorjetas Web3 (USDC na Base)
66socket.on("tip:new", (tip: TipEvent) => {
67 console.log("💰 Nova gorjeta onchain detectada:", tip.txHash);
68 sendMessage(
69 `💎 ${tip.donorAddress.slice(0, 6)}... enviou US$ ${tip.amountUsd.toFixed(2)} em USDC! "${tip.message ?? ""}"`
70 );
71});
72
73// Listener de Votos para o Spotlight
74socket.on("vote:cast", (vote: { channelId: string; amount: number; totalVotes: number }) => {
75 console.log(`⭐ + ${vote.amount} votos computados. Total: ${vote.totalVotes}`);
76});
77
78// Tratamento de erros do sistema
79socket.on("system:error", (err: { code: string; message: string }) => {
80 console.error("⚠️ [Sweetly Error]:", err.code, err.message);
81});
82
83function sendMessage(content: string) {
84 socket.emit("message:send", {
85 channelId: CHANNEL_ID,
86 content,
87 });
88}
Referência HTTP

Endpoints HTTP v1

Todos os endpoints RESTful estão hospedados sob https://sweetly.live/api. Respostas são retornadas em JSON com cabeçalhos CORS habilitados.

GET/api/channel
Session Cookie

Obter Dados do Canal Autenticado

Retorna as informações do canal do streamer autenticado pela sessão atual (slug, streamKey, followerCount, status de live, bio, avatares).

Exemplo de Resposta (200 OK)
json
{
"channel": {
"id": "c1f7a22e-1b3c-4e89-91a1-f3b9a1e09bc4",
"userId": "u8b2a19c-4c6e-41d3-a002-e612f00a5812",
"slug": "sweetstreamer",
"title": "Build & Chill: Coding Web3 DApps na Base",
"bio": "Desenvolvedor full-stack e streamer de código.",
"isLive": true,
"streamKey": "live_sec_9fa81bc328904712",
"category": "Software & Game Dev",
"avatarUrl": "https://sweetly.live/avatars/streamer.png",
"bannerUrl": "https://sweetly.live/banners/streamer.png",
"notificationMessage": "Entrei ao vivo! Vem codar junto.",
"followerCount": 4210,
"createdAt": "2025-01-10T12:00:00Z"
}
}
Exemplo de Chamada (cURL)
bash
curl -X GET "https://sweetly.live/api/channel" \
-H "Cookie: better-auth.session_token=SEU_TOKEN_AQUI"
PATCH/api/channel
Session Cookie

Atualizar Configurações do Canal

Permite atualizar o título da stream, categoria, status de transmissão (isLive), URLs de avatar/banner e mensagem automática de notificação.

Corpo da Requisição (JSON)
json
{
"title"?: string (3 a 140 caracteres),
"bio"?: string (máx 500 caracteres),
"category"?: string (máx 60 caracteres),
"avatarUrl"?: string (URL válida ou vazio),
"bannerUrl"?: string (URL válida ou vazio),
"notificationMessage"?: string (máx 280 caracteres),
"isLive"?: boolean
}
Exemplo de Resposta (200 OK)
json
{
"channel": {
"id": "c1f7a22e-1b3c-4e89-91a1-f3b9a1e09bc4",
"slug": "sweetstreamer",
"title": "Nova Transmissão: Testando Smart Contracts na Base",
"isLive": true,
"category": "Web3 & Crypto",
"updatedAt": "2025-02-01T15:30:00Z"
}
}
Exemplo de Chamada (cURL)
bash
curl -X PATCH "https://sweetly.live/api/channel" \
-H "Content-Type: application/json" \
-H "Cookie: better-auth.session_token=SEU_TOKEN_AQUI" \
-d '{"title": "Nova Transmissão: Testando Smart Contracts na Base", "isLive": true}'
GET/api/live/{channelSlug}
Público

Playlist HLS & Manifest DVR

Retorna a playlist dinâmica HLS (.m3u8) para reprodução em tempo real com suporte a janela deslizante de DVR (retroceder transmissão ao vivo).

Parâmetros de Rota
CampoTipoDescrição
channelSlugstring (path)Slug identificador do canal do streamer (ex: 'sweetstreamer' ou 'main')
Exemplo de Resposta (200 OK)
json
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:1542
#EXTINF:10.000,
https://cdn.sweetly.live/hls/sweetstreamer/segment_1542.ts
#EXTINF:10.000,
https://cdn.sweetly.live/hls/sweetstreamer/segment_1543.ts
Exemplo de Chamada (cURL)
bash
curl -X GET "https://sweetly.live/api/live/sweetstreamer"
GET/api/categories
Público

Listar Categorias de Lives

Retorna a lista de todas as categorias ativas com a soma agregada de espectadores ao vivo e total de canais transmitindo.

Exemplo de Resposta (200 OK)
json
[
{
"id": "cat-uuid-001",
"slug": "software-dev",
"name": "Software & Game Dev",
"coverUrl": "https://sweetly.live/categories/dev.jpg",
"liveViewers": 1840,
"liveChannels": 12
},
{
"id": "cat-uuid-002",
"slug": "web3-crypto",
"name": "Web3 & Crypto",
"coverUrl": "https://sweetly.live/categories/web3.jpg",
"liveViewers": 3410,
"liveChannels": 28
}
]
Exemplo de Chamada (cURL)
bash
curl -X GET "https://sweetly.live/api/categories"
GET/api/livenow
Público

Streams Ativas & Viewers

Lista todas as transmissões ao vivo atualmente no ar, ordenadas pelo número de espectadores em pico e atividade de comunidade.

Exemplo de Resposta (200 OK)
json
[
{
"id": "channel-uuid-1",
"slug": "cryptodev",
"title": "Criando Bots em Rust e Base L2",
"category": "Software & Game Dev",
"displayName": "Alex Dev",
"username": "cryptodev",
"avatarUrl": "https://sweetly.live/avatars/alex.png",
"viewerCount": 782,
"followerCount": 5120
}
]
Exemplo de Chamada (cURL)
bash
curl -X GET "https://sweetly.live/api/livenow"
POST/api/tips/verify
Público

Verificar Gorjeta Onchain em USDC

Submete o hash da transação executada na Base Mainnet para verificação e confirmação onchain. O contrato de USDC é consultado para validar o remetente, destinatário e valor transferido.

Corpo da Requisição (JSON)
json
{
"txHash": "0x..." (hash de 66 caracteres com prefixo 0x),
"streamId": "uuid" (ID da sessão de transmissão ativa),
"creatorAddress": "0x..." (endereço EVM do criador que recebe a gorjeta),
"amount": number (mínimo US$ 1.00, máximo US$ 1000.00),
"message": string (máximo 500 caracteres)
}
Exemplo de Resposta (200 OK)
json
{
"tip": {
"id": "tip-uuid-9812",
"txHash": "0x4e6b...81a0",
"donorAddress": "0x71C...92A1",
"creatorAddress": "0x892...11E4",
"amountUsd": "15.00",
"message": "Parabéns pela live!",
"status": "confirmed",
"createdAt": "2025-02-01T15:35:10Z"
}
}
Exemplo de Chamada (cURL)
bash
curl -X POST "https://sweetly.live/api/tips/verify" \
-H "Content-Type: application/json" \
-d '{
"txHash": "0x4e6b219e7a...81a0",
"streamId": "23a1e948-...",
"creatorAddress": "0x892a012...",
"amount": 10.0,
"message": "Ótima transmissão!"
}'
POST/api/keeper
Bearer Secret

Gatilho de Automação do Keeper Onchain

Dispara a rotina automatizada de verificação e execução de renovações de assinaturas expiradas do SubscriptionManager na Base. Requer token CRON_SECRET no cabeçalho Authorization.

Exemplo de Resposta (200 OK)
json
{
"status": "ok",
"processed": 14,
"renewed": 9,
"lapsed": 5
}
Exemplo de Chamada (cURL)
bash
curl -X POST "https://sweetly.live/api/keeper" \
-H "Authorization: Bearer CRON_SECRET_AQUI"
POST/api/channel/notify
Session Cookie

Notificar Seguidores de Início de Live

Dispara mensagens transacionais de alerta (por email e push) em lotes para os seguidores do canal assim que o streamer inicia a transmissão.

Exemplo de Resposta (200 OK)
json
{
"notified": 348
}
Exemplo de Chamada (cURL)
bash
curl -X POST "https://sweetly.live/api/channel/notify" \
-H "Cookie: better-auth.session_token=SEU_TOKEN_AQUI"
POST/api/clips
Público

Criar Clipe de Transmissão

Gera um clipe recortado a partir de um VOD ou gravação de transmissão. Duração suportada: entre 5 e 300 segundos.

Corpo da Requisição (JSON)
json
{
"vodId": "uuid" (ID do VOD de origem),
"title": string (1 a 120 caracteres),
"startSec": integer (segundo de início, >= 0),
"endSec": integer (segundo final, endSec - startSec entre 5 e 300)
}
Exemplo de Resposta (200 OK)
json
{
"id": "clip-uuid-5510",
"vodId": "vod-uuid-1122",
"title": "Melhor jogada do torneio!",
"playbackUrl": "https://cdn.sweetly.live/clips/clip-5510.mp4",
"durationSec": 45,
"views": 0,
"createdAt": "2025-02-01T16:00:00Z"
}
Exemplo de Chamada (cURL)
bash
curl -X POST "https://sweetly.live/api/clips" \
-H "Content-Type: application/json" \
-d '{"vodId": "79b4a1...", "title": "Melhor momento", "startSec": 120, "endSec": 150}'
POST/api/follow
Session Cookie

Seguir Canal

Registra o usuário autenticado como seguidor de um canal específico.

Corpo da Requisição (JSON)
json
{
"channelId": "uuid" (ID do canal a seguir)
}
Exemplo de Resposta (200 OK)
json
{
"followerCount": 4211
}
Exemplo de Chamada (cURL)
bash
curl -X POST "https://sweetly.live/api/follow" \
-H "Content-Type: application/json" \
-H "Cookie: better-auth.session_token=SEU_TOKEN_AQUI" \
-d '{"channelId": "c1f7a22e-1b3c-4e89-91a1-f3b9a1e09bc4"}'
POST/api/v1/channels/:slug/chat
Bearer Secret

Enviar Mensagem no Chat como Bot (v1)

Permite que bots e automações enviem mensagens e alertas de chat no feed do canal especificado pelo slug.

Parâmetros de Rota
CampoTipoDescrição
slugstring (path)Slug do canal alvo (ex: 'sweetstreamer')
Corpo da Requisição (JSON)
json
{
"content": string (1 a 500 caracteres),
"botName"?: string (nome personalizado do bot, máx 32 caracteres)
}
Exemplo de Resposta (200 OK)
json
{
"message": {
"id": "msg-uuid-9921",
"channelId": "c1f7a22e-1b3c-4e89-91a1-f3b9a1e09bc4",
"content": "🤖 Bot online e monitorando o canal!",
"username": "SweetlyBot",
"createdAt": "2025-02-01T16:10:00Z"
}
}
Exemplo de Chamada (cURL)
bash
curl -X POST "https://sweetly.live/api/v1/channels/sweetstreamer/chat" \
-H "Content-Type: application/json" \
-H "X-Sweetly-Bot-Token: SEU_BOT_TOKEN" \
-d '{"content": "Alerta de sorteio iniciado!", "botName": "SorteioBot"}'
GET/api/v1/channels/:slug/votes
Público

Votação & Ranking Spotlight do Canal (v1)

Retorna a pontuação de votos do canal, multiplicador de recompensas, época ativa e ranking no Spotlight.

Parâmetros de Rota
CampoTipoDescrição
slugstring (path)Slug do canal pesquisado
Exemplo de Resposta (200 OK)
json
{
"slug": "sweetstreamer",
"votes": 12850,
"rank": 3,
"multiplier": 1.45,
"epoch": 8
}
Exemplo de Chamada (cURL)
bash
curl -X GET "https://sweetly.live/api/v1/channels/sweetstreamer/votes"
GET/api/v1/contracts
Público

Contratos Web3 Oficiais (v1)

Retorna os endereços ativos e ABIs dos smart contracts na Base Mainnet (8453) e Base Sepolia (84532).

Exemplo de Resposta (200 OK)
json
{
"network": "Base",
"chainId": 8453,
"contracts": {
"subscriptionManager": {
"address": "0x0000000000000000000000000000000000000000"
},
"usdc": {
"address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"symbol": "USDC",
"decimals": 6
}
}
}
Exemplo de Chamada (cURL)
bash
curl -X GET "https://sweetly.live/api/v1/contracts"
Tempo Real

WebSocket & Socket.IO para Bots

O chat, moderação e eventos onchain do Sweetly operam sobre o protocolo Socket.IO v4. Os bots podem conectar diretamente no endpoint raiz e ouvir os eventos da sala de qualquer streamer.

Host do Servidor de Sockets:wss://sweetly.live
Transporte Recomendado:websocket (sem fallback polling para latência de 1 dígito)

Eventos do Cliente (Client → Server)

Eventos emitidos pelo bot para o servidor:

EventoPayloadDescrição
channel:join{ channelId: string }Ingressa na sala de chat de uma live para receber o feed de mensagens.
channel:leave{ channelId?: string }Sai da sala de chat e cancela o recebimento de transmissões daquele canal.
message:send{ channelId, content, parentId? }Envia uma mensagem de texto (máx 500 caracteres). Suporta responder mensagem via parentId.
message:delete{ messageId: string }Apaga uma mensagem do feed (requer papel de moderador ou criador).
message:pin{ messageId: string }Fixa uma mensagem no topo do chat para todos os espectadores.
mod:timeout{ channelId, targetUserId, durationSec }Aplica silenciamento temporário no usuário alvo pelo número de segundos.
mod:ban{ channelId, targetUserId }Bane permanentemente o usuário da sala de chat do canal.
command{ command: string, args: string[] }Executa slash command autorizado (/mod, /vip, /ban, /mods, /vips).

Eventos do Servidor (Server → Client)

Eventos que o bot deve ouvir e reagir:

EventoPayloadDescrição
message:newChatMessage (id, userId, username, content, mentions...)Disparado sempre que uma mensagem é validada e enviada no canal.
message:deleted{ messageId: string }Notifica que uma mensagem foi apagada por um moderador.
message:pinned{ messageId: string }Notifica alteração na mensagem fixada do canal.
mod:action{ channelId, action: "timeout"|"ban" }Informa ações disciplinares executadas na sala.
system:error{ code: string, message: string }Retornado em caso de comando inválido, permissão negada ou falha.

Slash Commands Nativos & Moderação

O servidor possui comandos embutidos com controle de permissões por papel (broadcaster, mod, vip, og):

/ban <user>

Bane permanentemente o usuário da transmissão. (Requer Moderador)

/mod <user>

Concede status e badge de Moderador do canal. (Requer Criador)

/vip <user>

Concede badge VIP e imunidade a slow mode. (Requer Criador)

/og <user>

Concede badge comemorativa de OG (Original Gangster). (Requer Criador)

/mods

Lista todos os moderadores com acesso ativo na sala.

/vips

Lista todos os membros VIP reconhecidos pelo canal.

Eventos Web3 em Tempo Real (Tips, Inscrições e Votos)

O backend do Sweetly escuta transações confirmadas na blockchain Base e emite eventos especiais pelo WebSocket para que os bots executem ações automáticas de engajamento (como alertas visuais, text-to-speech ou recompensas).

tip:newGorjeta em USDC Confirmada

Emitido quando o endpoint /api/tips/verify valida a transferência do token USDC na Base.

typescript
socket.on("tip:new", (data) => {
console.log("Doador:", data.donorAddress);
console.log("Valor:", data.amountUsd, "USDC");
console.log("Mensagem:", data.message);
console.log("Transação:", data.txHash);
});
vote:castVoto para Ranking Spotlight

Emitido quando os espectadores votam na live para elevar o canal no ranking comunitário.

typescript
socket.on("vote:cast", (data) => {
console.log("Canal:", data.channelId);
console.log("Votos somados:", data.amount);
console.log("Total acumulado:", data.totalVotes);
});
Smart Contracts

Smart Contracts na Rede Base

Toda a camada financeira e de propriedade de conteúdo do Sweetly é construída nativamente na rede Base (L2 do Ethereum com taxas mínimas e tempos de bloco de ~2 segundos).

RecursoBase Mainnet (8453)Base Sepolia (84532)
USDC Nativo0x833589fCD6eDb6E08f4c7C32D4f71b54bdA029130x036CbD53842c5426634e7929541eC2318f3dCF7e
SubscriptionManager0x00000000000000000000000000000000000000000x0000000000000000000000000000000000000000
Decimais USDC6 decimais (1 USDC = 1.000.000)6 decimais
Preço Assinatura5.00 USDC / 30 dias5.00 USDC / 30 dias

O Contrato SubscriptionManager

O contrato gerencia assinaturas onchain sem necessidade de custódia centralizada.

subscribe(address creator)

Transfere exatamente 5 USDC da carteira do assinante para a carteira do criador via transferFrom, registrando o carimbo de data/hora de término em 30 dias a partir do bloco atual.

renew(address subscriber, address creator)

Permite que a carteira autorizada do Keeper renove a assinatura na janela entre 2 dias antes e 3 dias depois da expiração, garantindo continuidade sem interrupção de benefícios.

cancel(address creator)

Revoga imediatamente o registro de assinatura ativa daquele criador na carteira do remetente.

isSubscribed(address subscriber, address creator)

Função view gratuita que retorna um booleano indicando se a assinatura permanece válida no momento atual.

ABI do SubscriptionManager (JSON)15 Itens

Copie esta ABI para usar no ethers.js, viem, wagmi, Web3.py ou hardhat.

SubscriptionManager.abi.json
json
1[
2 {
3 "type": "constructor",
4 "inputs": [
5 {
6 "name": "usdcAddress",
7 "type": "address",
8 "internalType": "address"
9 },
10 {
11 "name": "keeperAddress",
12 "type": "address",
13 "internalType": "address"
14 }
15 ],
16 "stateMutability": "nonpayable"
17 },
18 {
19 "type": "error",
20 "name": "InvalidAddress",
21 "inputs": []
22 },
23 {
24 "type": "error",
25 "name": "OnlyKeeper",
26 "inputs": []
27 },
28 {
29 "type": "error",
30 "name": "OutsideRenewalWindow",
31 "inputs": []
32 },
33 {
34 "type": "error",
35 "name": "PaymentFailed",
36 "inputs": []
37 },
38 {
39 "type": "event",
40 "name": "Subscribed",
41 "inputs": [
42 {
43 "name": "subscriber",
44 "type": "address",
45 "indexed": true,
46 "internalType": "address"
47 },
48 {
49 "name": "creator",
50 "type": "address",
51 "indexed": true,
52 "internalType": "address"
53 },
54 {
55 "name": "expiresAt",
56 "type": "uint256",
57 "indexed": false,
58 "internalType": "uint256"
59 }
60 ],
61 "anonymous": false
62 },
63 {
64 "type": "event",
65 "name": "Renewed",
66 "inputs": [
67 {
68 "name": "subscriber",
69 "type": "address",
70 "indexed": true,
71 "internalType": "address"
72 },
73 {
74 "name": "creator",
75 "type": "address",
76 "indexed": true,
77 "internalType": "address"
78 },
79 {
80 "name": "expiresAt",
81 "type": "uint256",
82 "indexed": false,
83 "internalType": "uint256"
84 }
85 ],
86 "anonymous": false
87 },
88 {
89 "type": "event",
90 "name": "Cancelled",
91 "inputs": [
92 {
93 "name": "subscriber",
94 "type": "address",
95 "indexed": true,
96 "internalType": "address"
97 },
98 {
99 "name": "creator",
100 "type": "address",
101 "indexed": true,
102 "internalType": "address"
103 }
104 ],
105 "anonymous": false
106 },
107 {
108 "type": "function",
109 "name": "cancel",
110 "inputs": [
111 {
112 "name": "creator",
113 "type": "address",
114 "internalType": "address"
115 }
116 ],
117 "outputs": [],
118 "stateMutability": "nonpayable"
119 },
120 {
121 "type": "function",
122 "name": "isSubscribed",
123 "inputs": [
124 {
125 "name": "subscriber",
126 "type": "address",
127 "internalType": "address"
128 },
129 {
130 "name": "creator",
131 "type": "address",
132 "internalType": "address"
133 }
134 ],
135 "outputs": [
136 {
137 "name": "",
138 "type": "bool",
139 "internalType": "bool"
140 }
141 ],
142 "stateMutability": "view"
143 },
144 {
145 "type": "function",
146 "name": "keeper",
147 "inputs": [],
148 "outputs": [
149 {
150 "name": "",
151 "type": "address",
152 "internalType": "address"
153 }
154 ],
155 "stateMutability": "view"
156 },
157 {
158 "type": "function",
159 "name": "renew",
160 "inputs": [
161 {
162 "name": "subscriber",
163 "type": "address",
164 "internalType": "address"
165 },
166 {
167 "name": "creator",
168 "type": "address",
169 "internalType": "address"
170 }
171 ],
172 "outputs": [],
173 "stateMutability": "nonpayable"
174 },
175 {
176 "type": "function",
177 "name": "subscribe",
178 "inputs": [
179 {
180 "name": "creator",
181 "type": "address",
182 "internalType": "address"
183 }
184 ],
185 "outputs": [],
186 "stateMutability": "nonpayable"
187 },
188 {
189 "type": "function",
190 "name": "subscriptions",
191 "inputs": [
192 {
193 "name": "subscriber",
194 "type": "address",
195 "internalType": "address"
196 },
197 {
198 "name": "creator",
199 "type": "address",
200 "internalType": "address"
201 }
202 ],
203 "outputs": [
204 {
205 "name": "expiresAt",
206 "type": "uint256",
207 "internalType": "uint256"
208 }
209 ],
210 "stateMutability": "view"
211 },
212 {
213 "type": "function",
214 "name": "usdc",
215 "inputs": [],
216 "outputs": [
217 {
218 "name": "",
219 "type": "address",
220 "internalType": "contract IERC20"
221 }
222 ],
223 "stateMutability": "view"
224 }
225]

Interagindo via Código (Viem & Web3.py)

Veja como aprovar USDC e assinar um criador diretamente via smart contract:

typescript
1import { createPublicClient, createWalletClient, custom, http, parseUnits } from "viem";
2import { base } from "viem/chains";
3import { subscriptionManagerAbi, subscriptionManagerAddresses, usdcAddresses } from "@sweetly/contracts";
4
5// 1. Configuração do cliente na Base Mainnet (Chain ID 8453)
6const publicClient = createPublicClient({
7 chain: base,
8 transport: http("https://mainnet.base.org"),
9});
10
11const walletClient = createWalletClient({
12 chain: base,
13 transport: custom(window.ethereum),
14});
15
16const USDC_ADDRESS = usdcAddresses[base.id];
17const MANAGER_ADDRESS = subscriptionManagerAddresses[base.id];
18const MONTHLY_PRICE = parseUnits("5", 6); // 5 USDC (6 decimais = 5_000_000)
19
20export async function subscribeToCreator(creatorAddress: `0x${string}`) {
21 const [account] = await walletClient.getAddresses();
22 if (!account) throw new Error("Carteira nao conectada");
23
24 // Passo 1: Aprovar o SubscriptionManager a movimentar 5 USDC
25 const erc20Abi = [
26 {
27 name: "approve",
28 type: "function",
29 inputs: [{ name: "spender", type: "address" }, { name: "amount", type: "uint256" }],
30 outputs: [{ name: "", type: "bool" }],
31 stateMutability: "nonpayable",
32 },
33 ] as const;
34
35 console.log("1. Aprovando transferencia de 5 USDC...");
36 const approveHash = await walletClient.writeContract({
37 address: USDC_ADDRESS,
38 abi: erc20Abi,
39 functionName: "approve",
40 args: [MANAGER_ADDRESS, MONTHLY_PRICE],
41 account,
42 });
43
44 await publicClient.waitForTransactionReceipt({ hash: approveHash });
45 console.log("Aprovado com sucesso!");
46
47 // Passo 2: Executar a assinatura
48 console.log("2. Chamando subscribe(creator)...");
49 const subscribeHash = await walletClient.writeContract({
50 address: MANAGER_ADDRESS,
51 abi: subscriptionManagerAbi,
52 functionName: "subscribe",
53 args: [creatorAddress],
54 account,
55 });
56
57 const receipt = await publicClient.waitForTransactionReceipt({ hash: subscribeHash });
58 console.log("🎉 Assinatura confirmada no bloco:", receipt.blockNumber);
59 return receipt;
60}
Boas Práticas

Boas Práticas e Limites de Requisição

Para proteger a estabilidade do ecossistema e evitar sobrecarga nos nós RPC e servidores de chat, siga as diretrizes de rate limiting e resiliência:

Limites de Requisição HTTP (Rate Limits)

60 requisições / minuto

Para clientes não autenticados ou chamadas públicas anônimas.

120 requisições / minuto

Para sessões autenticadas de criadores e bots com credenciais válidas.

Tratamento do Erro HTTP 429

Caso o limite seja excedido, a API responderá com status 429 Too Many Requests e o cabeçalho Retry-After: <segundos>. Seu bot deve respeitar esse intervalo antes de reenviar chamadas.

Resiliência e Reconexão Socket.IO

Em conexões WebSocket contínuas, oscilações de rede são comuns. Utilize sempre reconexão com backoff exponencial e re-envio de channel:join no evento connect:

typescript
// Padrão resiliente para bots de produção:
const socket = io("https://sweetly.live", {
transports: ["websocket"],
reconnection: true,
reconnectionAttempts: Infinity,
reconnectionDelay: 1000,
reconnectionDelayMax: 10000,
randomizationFactor: 0.5, // Adiciona jitter para evitar tempestades de reconexão
});
socket.on("connect", () => {
// Sempre reingressar na sala após reconectar
socket.emit("channel:join", { channelId: CURRENT_CHANNEL });
});

Segurança de Chaves e Carteiras

Nunca Exponha Chaves Privadas

Armazene chaves de API, chaves privadas da carteira e segredos do Keeper em variáveis de ambiente (.env). Jamais faça commit desses valores no Git ou os envie em mensagens de chat.

Contas de Bot Dedicadas

Para bots de chat e moderação, crie uma conta separada e solicite ao streamer que conceda a role de /mod no canal, mantendo a conta principal do streamer protegida.

Pronto para construir o futuro do streaming?

Acesse o painel do criador ou conecte seu bot agora mesmo na rede Base.