Skip to main content
Glama

BSC MCP Server

util.ts9.58 kB
import { type Hex } from "viem"; import { exec } from 'child_process'; import fs from 'fs'; import path from 'path'; import os from 'os'; import { decryptPrivateKey, } from "./PrivateAES.js"; import { privateKeyToAccount } from "viem/accounts"; import { publicClient } from "./config.js"; const platform = os.platform(); export function buildTxUrl(txHash: Hex | undefined): string | undefined { if (!txHash) { return undefined; } const txUrl = `https://bscscan.com/tx/${txHash}`; return txUrl } export async function checkTransactionHash(txHash: Hex): Promise<string> { const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash, retryCount: 300, retryDelay: 100, }); const txUrl = `https://bscscan.com/tx/${txHash}`; if (txReceipt.status !== "success") { throw new Error(`Please check the transaction results on bscscan, ${txUrl}`); } return txUrl; } export function bigIntReplacer(key: string, value: any) { return typeof value === 'bigint' ? value.toString() : value; } export interface InputBoxOptions { title?: string; message?: string; defaultValue?: string; termsText?: string; } export interface InputResult { value: string | null; agreed: boolean; } let passwordLock = false export async function getPassword(isRetry?: boolean, num = 0): Promise<InputResult> { if (passwordLock) { throw new Error("Password lock is enabled. Try again in 24 hours"); } if (num > 10) { passwordLock = true; setTimeout(() => { passwordLock = false; }, 1000 * 60 * 60 * 24); throw new Error("You have entered the wrong password too many times."); } const passwordResp = await showInputBoxWithTerms(isRetry); if (!passwordResp.value) { throw new Error("You did not enter a password."); } if (passwordResp.value.length < 8 || passwordResp.value.length > 128) { throw new Error("The password must be between 8 and 128 characters."); } const password = passwordResp.value; const BSC_WALLET_PRIVATE_KEY = process.env.BSC_WALLET_PRIVATE_KEY as Hex if (!BSC_WALLET_PRIVATE_KEY) { throw new Error("BSC_WALLET_PRIVATE_KEY is not defined"); } try { const pk = await decryptPrivateKey(BSC_WALLET_PRIVATE_KEY, password) const account = privateKeyToAccount( pk as Hex ); const address = process.env.BSC_WALLET_ADDRESS if (!address) { throw new Error("BSC_WALLET_ADDRESS is not defined"); } if (account.address != address) { return await getPassword(true, ++num); } } catch (error) { if (error instanceof Error) { if (error.message === "Password lock is enabled. Try again in 24 hours") { throw error; } if (error.message === "You have entered the wrong password too many times.") { throw error; } } return await getPassword(true, ++num); } return passwordResp; } export function showInputBoxWithTerms(isRetry?: boolean): Promise<InputResult> { let message = "Enter your Wallet Password:"; if (isRetry) { message = "Wrong password, please try again:"; } return new Promise((resolve, reject) => { switch (platform) { case 'darwin': // For macOS, we use AppleScript to show a dialog with both input and checkbox // The AppleScript is more complex but allows for a better UX if (isRetry) { message = "❌" + message } const appleScript = ` tell application "System Events" set userPassword to "" set buttonPressed to "" repeat try set userInput to display dialog "${message}" default answer "" with hidden answer buttons {"cancel", "confirm"} default button "confirm" with icon note set userPassword to text returned of userInput set buttonPressed to button returned of userInput if buttonPressed is "cancel" then exit repeat end if if (length of userPassword >= 8) and (length of userPassword <= 128) then exit repeat end if display dialog "Wallet Password must be between 8 and 128 characters!" buttons {"confirm"} default button "confirm" with icon caution on error -- Handle any errors (like when user clicks the red close button) exit repeat end try end repeat if buttonPressed is not "cancel" then set agreeToTerms to button returned of (display dialog "🔒 You will stay signed in for the next hour." buttons {"no", "yes"} default button "no" with icon caution) return userPassword & "============" & agreeToTerms else return "canceled" end if end tell `; exec(`osascript -e '${appleScript}'`, (error, stdout, stderr) => { if (error) { // User cancelled if (error.code === 1 || error.code === 255) { resolve({ value: null, agreed: false }); } else { reject(error); } return; } if (stdout.trim() === "canceled") { reject(new Error("Please enter the password before using ❕")); return; } const [password, agree] = stdout.trim().split("============"); resolve({ value: password, agreed: agree === "yes" }); }); break; case 'win32': const winCommand = ` Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing $form = New-Object System.Windows.Forms.Form $form.Text = 'wallet password' $form.Size = New-Object System.Drawing.Size(450,300) $form.StartPosition = 'CenterScreen' $label = New-Object System.Windows.Forms.Label $label.Location = New-Object System.Drawing.Point(10,20) $label.Size = New-Object System.Drawing.Size(380,40) $label.Text = '${message}' $form.Controls.Add($label) # User input label $userLabel = New-Object System.Windows.Forms.Label $userLabel.Location = New-Object System.Drawing.Point(10,70) $userLabel.Size = New-Object System.Drawing.Size(150,20) $userLabel.Text = 'Input Password:' $form.Controls.Add($userLabel) # User input textbox $passwordTextBox = New-Object System.Windows.Forms.TextBox $passwordTextBox.Location = New-Object System.Drawing.Point(160,70) $passwordTextBox.Size = New-Object System.Drawing.Size(250,20) $passwordTextBox.PasswordChar = '*' $form.Controls.Add($passwordTextBox) # Error message label $errorLabel = New-Object System.Windows.Forms.Label $errorLabel.Location = New-Object System.Drawing.Point(160,95) $errorLabel.Size = New-Object System.Drawing.Size(250,20) $errorLabel.ForeColor = [System.Drawing.Color]::Red $errorLabel.Text = '' $form.Controls.Add($errorLabel) $checkbox = New-Object System.Windows.Forms.CheckBox $checkbox.Location = New-Object System.Drawing.Point(10,130) $checkbox.Size = New-Object System.Drawing.Size(350,20) $checkbox.Text = 'You will stay signed in for the next hour.' $form.Controls.Add($checkbox) $button = New-Object System.Windows.Forms.Button $button.Location = New-Object System.Drawing.Point(175,190) $button.Size = New-Object System.Drawing.Size(100,30) $button.Text = 'Confirm' $button.Add_Click({ # Validate password length if ($passwordTextBox.Text.Length -lt 8 -or $passwordTextBox.Text.Length -gt 128) { $errorLabel.Text = 'Wallet Password must be between 8 and 128 characters!' } else { $form.DialogResult = [System.Windows.Forms.DialogResult]::OK $form.Close() } }) $form.Controls.Add($button) $form.AcceptButton = $button $form.Add_Shown({$form.Activate()}) [void]$form.ShowDialog() if ($form.DialogResult -eq [System.Windows.Forms.DialogResult]::OK) { $result = @{ agreed = $checkbox.Checked value = $passwordTextBox.Text } $jsonResult = ConvertTo-Json -InputObject $result Write-Output $jsonResult } exit 0 ` const tempScriptPath = path.join('.', 'terms_form.ps1'); fs.writeFileSync(tempScriptPath, winCommand); exec(`powershell -ExecutionPolicy Bypass -File "${tempScriptPath}"`, (error, stdout, stderr) => { fs.unlinkSync(tempScriptPath); if (error && error.code !== 1) { resolve({ value: null, agreed: false }); return; } if (!stdout) { reject(new Error("Please enter the password before using ❕")); return; } const stdoutJSON = JSON.parse(stdout); resolve({ value: stdoutJSON.value as string, agreed: stdoutJSON.agreed as boolean }); }); break; default: reject(new Error(`Unsupported platform and command-line input is not available: ${platform}`)); } }); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/TermiX-official/bsc-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server