Skip to main content
Glama

bnbchain-mcp

Official
by bnb-chain
payment.ts9.63 kB
import { StreamAccountStatus } from "@bnb-chain/greenfield-cosmos-types/greenfield/payment/stream_record" import { Long } from "@bnb-chain/greenfield-js-sdk" import { Hex, parseEther } from "viem" import { selectSp } from "@/gnfd/services/sp" import { ApiResponse, response } from "../util" import { getAccount } from "./account" import { getClient } from "./client" import { executeTransaction } from "./common" type StoreFeeConfig = { readPrice: string primarySpStorePrice: string secondarySpStorePrice: string validatorTaxRate: string minChargeSize: number redundantDataChunkNum: number redundantParityChunkNum: number reserveTime: string } /** * Creates a payment account for the specified address * @param privateKey The private key for signing the transaction * @returns Transaction hash */ export const createPaymentAccount = async ( network: "testnet" | "mainnet", privateKey: Hex ): Promise<ApiResponse<{ txHash: string }>> => { try { const client = getClient(network) const account = await getAccount(network, privateKey) const createPaymentAccountTx = await client.account.createPaymentAccount({ creator: account.address }) const tx = await executeTransaction<{ txHash: string }>( createPaymentAccountTx, account, privateKey, "Create payment account", account.address ) return tx } catch (error: any) { return response.fail(`Failed to create payment account: ${error.message}`) } } /** * Deposits funds into a payment account * @param to The payment account address to deposit to * @param amount The amount to deposit (in BNB) * @param privateKey The private key for signing the transaction * @returns Transaction hash */ export const depositToPaymentAccount = async ( network: "testnet" | "mainnet", { to, amount, privateKey }: { to: string amount: string privateKey: Hex } ): Promise<ApiResponse<void>> => { try { const client = getClient(network) const account = await getAccount(network, privateKey) const depositTx = await client.payment.deposit({ creator: account.address, to, amount: parseEther(amount).toString() }) const tx = await executeTransaction<void>( depositTx, account, privateKey, "Deposit funds", `Deposit ${amount} BNB to ${to}` ) return tx } catch (error: any) { return response.fail(`Failed to deposit funds: ${error.message}`) } } /** * Withdraws funds from a payment account * @param from The payment account to withdraw from * @param amount The amount to withdraw (in BNB) * @param privateKey The private key for signing the transaction * @returns Transaction hash */ export const withdrawFromPaymentAccount = async ( network: "testnet" | "mainnet", { from, amount, privateKey }: { from: string amount: string privateKey: Hex } ): Promise<ApiResponse<void>> => { try { const client = getClient(network) const account = await getAccount(network, privateKey) const withdrawTx = await client.payment.withdraw({ creator: account.address, from, amount: parseEther(amount).toString() }) const tx = await executeTransaction<void>( withdrawTx, account, privateKey, "Withdraw funds", `Withdraw ${amount} BNB from ${from}` ) return tx } catch (error: any) { return response.fail(`Failed to withdraw funds: ${error.message}`) } } /** * Disables refund for a payment account * @warning ⚠️ CAUTION: This action is IRREVERSIBLE. Once disabled, ALL transfers to this payment account will become NON-REFUNDABLE. * @param address The payment account address to disable refund for * @param privateKey The private key for signing the transaction * @returns Transaction hash */ export const disableRefundForPaymentAccount = async ( network: "testnet" | "mainnet", { address, privateKey }: { address: string privateKey: Hex } ): Promise<ApiResponse<void>> => { try { const client = getClient(network) const account = await getAccount(network, privateKey) const disableRefundTx = await client.payment.disableRefund({ owner: account.address, addr: address }) const tx = await executeTransaction<void>( disableRefundTx, account, privateKey, "Disable refund", `Disable refund for ${address}` ) return tx } catch (error: any) { return response.fail(`Failed to disable refund: ${error.message}`) } } /** * Get a payment account info in Greenfield * @param network The network to use * @param paymentAddress The payment account address * @returns The payment account info */ export const getPaymentAccountInfo = async ( network: "testnet" | "mainnet", paymentAddress: string ) => { try { const client = getClient(network) const account = await client.payment.paymentAccount({ addr: paymentAddress }) const { streamRecord } = await client.payment.getStreamRecord(paymentAddress) const formattedStreamRecord = { owner: account.paymentAccount.owner, refundable: account.paymentAccount.refundable, paymentAddress, settleDate: new Date( Number(streamRecord.settleTimestamp) * 1000 ).toISOString(), updateDate: new Date( Number(streamRecord.crudTimestamp) * 1000 ).toISOString(), status: StreamAccountStatus[streamRecord.status], netflowRate: streamRecord.netflowRate, staticBalance: streamRecord.staticBalance, bufferBalance: streamRecord.bufferBalance, lockBalance: streamRecord.lockBalance, frozenNetflowRate: streamRecord.frozenNetflowRate } return response.success(formattedStreamRecord) } catch (error: any) { return response.fail(`Failed to get payment account info: ${error.message}`) } } /** * Get store fee calculation configuration in Greenfield */ const _getStoreFeeConfig = async ( network: "mainnet" | "testnet", timestamp?: number ) => { const client = getClient(network) const time = timestamp || Math.floor(+new Date() / 1000) const [ globalSpStoragePrice, { params: storageParams }, { params: paymentParams } ] = await Promise.all([ client.sp.getQueryGlobalSpStorePriceByTime({ timestamp: Long.fromNumber(time) }), client.storage.params(), client.payment.params() ]) const { minChargeSize = new Long(0), redundantDataChunkNum = 0, redundantParityChunkNum = 0 } = (storageParams && storageParams.versionedParams) || {} const { reserveTime, validatorTaxRate } = paymentParams?.versionedParams || {} return { primarySpStorePrice: globalSpStoragePrice?.globalSpStorePrice.primaryStorePrice || "", readPrice: globalSpStoragePrice?.globalSpStorePrice.readPrice || "", secondarySpStorePrice: globalSpStoragePrice?.globalSpStorePrice.secondaryStorePrice || "", validatorTaxRate: validatorTaxRate || "", minChargeSize: minChargeSize.toNumber(), redundantDataChunkNum, redundantParityChunkNum, reserveTime: reserveTime?.toString() || "" } } /** * Estimate the netflow rate per second for a specified size */ const _estimateStoreNetflowRate = ( size: number, storeFeeConfig: StoreFeeConfig, isChargeSize = false ) => { const { primarySpStorePrice, secondarySpStorePrice, redundantDataChunkNum, redundantParityChunkNum, minChargeSize, validatorTaxRate } = storeFeeConfig const chargeSize = isChargeSize ? size : size >= minChargeSize ? size : minChargeSize const primarySpRate = Number(primarySpStorePrice) * chargeSize const secondarySpNum = redundantDataChunkNum + redundantParityChunkNum let secondarySpRate = Number(secondarySpStorePrice) * chargeSize secondarySpRate = secondarySpRate * secondarySpNum const validatorTax = Number(validatorTaxRate) * (primarySpRate + secondarySpRate) const netflowRate = primarySpRate + secondarySpRate + validatorTax return netflowRate / 10 ** 18 } /** * Get the related buckets for a payment account */ export const getPaymentAccountRelatedBuckets = async ( network: "testnet" | "mainnet", { paymentAddress, privateKey }: { paymentAddress: string privateKey: Hex } ) => { try { const client = getClient(network) const sp = await selectSp(network) const storeFeeConfig = await _getStoreFeeConfig(network) const ownerAccount = (await getAccount(network, privateKey)).address const buckets = await client.bucket.listBuckets({ address: ownerAccount, endpoint: sp.endpoint }) const { streamRecord } = await client.payment.getStreamRecord(paymentAddress) const relatedBuckets = buckets.body ?.filter((bucket) => { return ( bucket.BucketInfo.PaymentAddress.toLowerCase() === paymentAddress.toLowerCase() ) }) .map((bucket) => ({ ...bucket, settlementDate: new Date( Number(streamRecord.settleTimestamp) * 1000 ).toISOString(), netflowRateInSeconds: _estimateStoreNetflowRate( // @ts-ignore bucket.StorageSize, storeFeeConfig ), netflowRateInDays: // @ts-ignore _estimateStoreNetflowRate(bucket.StorageSize, storeFeeConfig) * 86400 })) return response.success(relatedBuckets) } catch (error: any) { return response.fail( `Failed to get payment account related buckets: ${error.message}` ) } }

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/bnb-chain/bnbchain-mcp'

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