文件内容
references/INTERACTIVE.md
# Interactive Components
## Send Button Form
```typescript
await handler.sendInteractionRequest(channelId, {
type: 'form', // NOT 'case'
id: 'my-form',
components: [
{ id: 'yes', type: 'button', label: 'Yes' },
{ id: 'no', type: 'button', label: 'No' }
],
recipient: event.userId // Optional: private to this user
})
```
## Handle Form Response
```typescript
bot.onInteractionResponse(async (handler, event) => {
if (event.response.payload.content?.case !== 'form') return
const form = event.response.payload.content.value
for (const c of form.components) {
if (c.component.case === 'button') {
console.log('Button clicked:', c.id)
if (c.id === 'yes') {
await handler.sendMessage(event.channelId, 'You clicked Yes!')
}
}
}
})
```
## Request Transaction
```typescript
import { encodeFunctionData, erc20Abi, parseUnits } from 'viem'
await handler.sendInteractionRequest(channelId, {
type: 'transaction',
id: 'payment',
title: 'Send Tokens',
subtitle: 'Transfer 50 USDC',
tx: {
chainId: '8453',
to: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC
value: '0',
data: encodeFunctionData({
abi: erc20Abi,
functionName: 'transfer',
args: [recipient, parseUnits('50', 6)]
})
},
recipient: event.userId
})
```
## Handle Transaction Response
```typescript
bot.onInteractionResponse(async (handler, event) => {
if (event.response.payload.content?.case !== 'transaction') return
const tx = event.response.payload.content.value
if (tx.txHash) {
// IMPORTANT: Always verify on-chain before granting access
// See BLOCKCHAIN.md for full verification pattern
const receipt = await waitForTransactionReceipt(bot.viem, {
hash: tx.txHash
})
if (receipt.status === 'success') {
await handler.sendMessage(event.channelId,
'Payment confirmed: https://basescan.org/tx/' + tx.txHash)
} else {
await handler.sendMessage(event.channelId, 'Transaction failed on-chain')
}
} else if (tx.error) {
await handler.sendMessage(event.channelId, 'Transaction rejected: ' + tx.error)
}
})
```
## Request Signature
```typescript
await handler.sendInteractionRequest(channelId, {
type: 'signature',
id: 'sign-message',
title: 'Sign Message',
message: 'I agree to the terms of service',
recipient: event.userId
})
```
## Important Notes
- **Use `type` property** - NOT `case` (common mistake)
- **`recipient` is optional** - If set, only that user sees the interaction
- **Always verify transactions** - Never trust txHash alone, check receipt.status