refactor: rename SolaceScanScout to Solace and update related configurations

- Updated branding from "SolaceScanScout" to "Solace" across various files including deployment scripts, API responses, and documentation.
- Changed default base URL for Playwright tests and updated security headers to reflect the new branding.
- Enhanced README and API documentation to include new authentication endpoints and product access details.

This refactor aligns the project branding and improves clarity in the API documentation.
This commit is contained in:
defiQUG
2026-04-10 12:52:17 -07:00
parent 6eef6b07f6
commit 0972178cc5
160 changed files with 13274 additions and 1061 deletions

View File

@@ -1,5 +1,6 @@
import { apiClient, ApiResponse } from './client'
import { fetchBlockscoutJson, normalizeTransaction } from './blockscout'
import { ApiResponse } from './client'
import { fetchBlockscoutJson, normalizeTransaction, type BlockscoutInternalTransaction } from './blockscout'
import { resolveExplorerApiBase } from '../../../libs/frontend-api-client/api-base'
export interface Transaction {
chain_id: number
@@ -19,6 +20,165 @@ export interface Transaction {
input_data?: string
contract_address?: string
created_at: string
fee?: string
method?: string
revert_reason?: string
transaction_tag?: string
decoded_input?: {
method_call?: string
method_id?: string
parameters: Array<{
name?: string
type?: string
value?: unknown
}>
}
token_transfers?: TransactionTokenTransfer[]
}
export interface TransactionTokenTransfer {
block_number?: number
from_address: string
from_label?: string
to_address: string
to_label?: string
token_address: string
token_name?: string
token_symbol?: string
token_decimals: number
amount: string
type?: string
timestamp?: string
}
export interface TransactionInternalCall {
from_address: string
from_label?: string
to_address?: string
to_label?: string
contract_address?: string
contract_label?: string
type?: string
value: string
success?: boolean
error?: string
result?: string
timestamp?: string
}
export interface TransactionLookupDiagnostic {
checked_hash: string
chain_id: number
explorer_indexed: boolean
rpc_transaction_found: boolean
rpc_receipt_found: boolean
latest_block_number?: number
rpc_url?: string
}
const CHAIN_138_PUBLIC_RPC_URL = 'https://rpc-http-pub.d-bis.org'
function resolvePublicRpcUrl(chainId: number): string | null {
if (chainId !== 138) {
return null
}
const envValue = (process.env.NEXT_PUBLIC_CHAIN_138_RPC_URL || '').trim()
return envValue || CHAIN_138_PUBLIC_RPC_URL
}
async function fetchJsonWithStatus<T>(input: RequestInfo | URL, init?: RequestInit): Promise<{ ok: boolean; status: number; data: T | null }> {
const response = await fetch(input, init)
let data: T | null = null
try {
data = (await response.json()) as T
} catch {
data = null
}
return { ok: response.ok, status: response.status, data }
}
async function fetchRpcResult<T>(rpcUrl: string, method: string, params: unknown[]): Promise<T | null> {
const controller = new AbortController()
const timeout = setTimeout(() => controller.abort(), 6000)
try {
const response = await fetch(rpcUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method,
params,
}),
signal: controller.signal,
})
if (!response.ok) {
return null
}
const payload = (await response.json()) as { result?: T | null }
return payload.result ?? null
} catch {
return null
} finally {
clearTimeout(timeout)
}
}
async function diagnoseMissingTransaction(chainId: number, hash: string): Promise<TransactionLookupDiagnostic> {
const diagnostic: TransactionLookupDiagnostic = {
checked_hash: hash,
chain_id: chainId,
explorer_indexed: false,
rpc_transaction_found: false,
rpc_receipt_found: false,
}
const explorerLookup = await fetchJsonWithStatus<unknown>(`${resolveExplorerApiBase()}/api/v2/transactions/${hash}`)
diagnostic.explorer_indexed = explorerLookup.ok
const rpcUrl = resolvePublicRpcUrl(chainId)
if (!rpcUrl) {
return diagnostic
}
diagnostic.rpc_url = rpcUrl
const [transactionResult, receiptResult, latestBlockHex] = await Promise.all([
fetchRpcResult<string | Record<string, unknown>>(rpcUrl, 'eth_getTransactionByHash', [hash]),
fetchRpcResult<string | Record<string, unknown>>(rpcUrl, 'eth_getTransactionReceipt', [hash]),
fetchRpcResult<string>(rpcUrl, 'eth_blockNumber', []),
])
diagnostic.rpc_transaction_found = transactionResult != null
diagnostic.rpc_receipt_found = receiptResult != null
if (typeof latestBlockHex === 'string' && latestBlockHex.startsWith('0x')) {
diagnostic.latest_block_number = parseInt(latestBlockHex, 16)
}
return diagnostic
}
function normalizeInternalTransactions(items: BlockscoutInternalTransaction[] | null | undefined): TransactionInternalCall[] {
if (!Array.isArray(items)) {
return []
}
return items.map((item) => ({
from_address: item.from?.hash || '',
from_label: item.from?.name || item.from?.label || undefined,
to_address: item.to?.hash || undefined,
to_label: item.to?.name || item.to?.label || undefined,
contract_address: item.created_contract?.hash || undefined,
contract_label: item.created_contract?.name || item.created_contract?.label || undefined,
type: item.type || undefined,
value: item.value || '0',
success: item.success ?? undefined,
error: item.error || undefined,
result: item.result || undefined,
timestamp: item.timestamp || undefined,
}))
}
export const transactionsApi = {
@@ -35,6 +195,20 @@ export const transactionsApi = {
return { ok: false, data: null }
}
},
diagnoseMissing: async (chainId: number, hash: string): Promise<TransactionLookupDiagnostic> => {
return diagnoseMissingTransaction(chainId, hash)
},
getInternalTransactionsSafe: async (hash: string): Promise<{ ok: boolean; data: TransactionInternalCall[] }> => {
try {
const raw = await fetchBlockscoutJson<{ items?: BlockscoutInternalTransaction[] } | BlockscoutInternalTransaction[]>(
`/api/v2/transactions/${hash}/internal-transactions`
)
const items = Array.isArray(raw) ? raw : raw.items
return { ok: true, data: normalizeInternalTransactions(items) }
} catch {
return { ok: false, data: [] }
}
},
list: async (chainId: number, page: number, pageSize: number): Promise<ApiResponse<Transaction[]>> => {
const params = new URLSearchParams({
page: page.toString(),