Copy import { privateKeyToAccount } from 'viem/accounts';
import { keccak256, toHex } from 'viem';
const GATEWAY_URL = 'https://x402.quickintel.io';
const account = privateKeyToAccount(process.env.PRIVATE_KEY);
async function scanToken(chain, tokenAddress) {
// 1. Get 402 response
const initial = await fetch(`${GATEWAY_URL}/v1/scan/full`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ chain, tokenAddress })
});
const { paymentRequired } = await initial.json();
const paymentInfo = paymentRequired.accepts.find(a => a.network === 'eip155:8453');
// 2. Sign payment
const nonce = keccak256(toHex(`${Date.now()}-${Math.random()}`));
const validBefore = BigInt(Math.floor(Date.now() / 1000) + 3600);
const signature = await account.signTypedData({
domain: {
name: paymentInfo.extra.name,
version: paymentInfo.extra.version,
chainId: 8453,
verifyingContract: paymentInfo.asset
},
types: {
TransferWithAuthorization: [
{ name: 'from', type: 'address' },
{ name: 'to', type: 'address' },
{ name: 'value', type: 'uint256' },
{ name: 'validAfter', type: 'uint256' },
{ name: 'validBefore', type: 'uint256' },
{ name: 'nonce', type: 'bytes32' }
]
},
primaryType: 'TransferWithAuthorization',
message: {
from: account.address,
to: paymentInfo.payTo,
value: BigInt(paymentInfo.maxAmountRequired),
validAfter: 0n,
validBefore,
nonce
}
});
const paymentPayload = btoa(JSON.stringify({
x402Version: 2,
scheme: 'exact',
network: 'eip155:8453',
payload: {
signature,
authorization: {
from: account.address,
to: paymentInfo.payTo,
value: paymentInfo.maxAmountRequired,
validAfter: '0',
validBefore: validBefore.toString(),
nonce
}
}
}));
// 3. Retry with payment
const response = await fetch(`${GATEWAY_URL}/v1/scan/full`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'PAYMENT-SIGNATURE': paymentPayload
},
body: JSON.stringify({ chain, tokenAddress })
});
return response.json();
}
// Usage
const result = await scanToken('base', '0x4ed4e862860bed51a9570b96d89af5e1b0efefed');
console.log(result);