/** * Component: TransactionsReceiptRow * Author: Nearblocks Pte Ltd * License: Business Source License 1.1 * Description: Details of Transaction Receipt Row on Near Protocol. * @interface Props * @param {string} [network] - The network data to show, either mainnet or testnet * @param {Function} [t] - A function for internationalization (i18n) provided by the next-translate package. * @param {TransactionInfo} [txn] - Information related to a transaction. * @param {RPCTransactionInfo} [rpcTxn] - RPC data of the transaction. * @param {ReceiptsPropsInfo} [receipt] - receipt of the transaction. */ /* INCLUDE COMPONENT: "includes/Common/Question.jsx" */ const Question = (props) => { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width={16} height={16} {...props} > <path fill="none" d="M0 0h24v24H0z" /> <path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 100-16 8 8 0 000 16zm-1-5h2v2h-2v-2zm2-1.645V14h-2v-1.5a1 1 0 011-1 1.5 1.5 0 10-1.471-1.794l-1.962-.393A3.501 3.501 0 1113 13.355z" /> </svg> ); };/* END_INCLUDE COMPONENT: "includes/Common/Question.jsx" */ /* INCLUDE: "includes/formats.jsx" */ function convertToMetricPrefix(number) { const prefixes = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']; // Metric prefixes let count = 0; while (Math.abs(number) >= 1000 && count < prefixes.length - 1) { number /= 1000; count++; } // Check if the number is close to an integer value if (Math.abs(number) >= 10) { number = Math.round(number); // Round the number to the nearest whole number return number + ' ' + prefixes[count]; } return ( Number(Math.floor(number * 100) / 100).toFixed(2) + ' ' + prefixes[count] ); } function formatNumber(value) { const suffixes = ['', 'K', 'M', 'B', 'T']; let suffixIndex = 0; while (value >= 10000 && suffixIndex < suffixes.length - 1) { value /= 1000; suffixIndex++; } const formattedValue = value.toFixed(1).replace(/\.0+$/, ''); return `${formattedValue} ${suffixes[suffixIndex]}`; } function gasFee(gas, price) { const near = yoctoToNear(Big(gas).mul(Big(price)).toString(), true); return `${near} Ⓝ`; } function currency(number) { let absNumber = Math.abs(number); const suffixes = ['', 'K', 'M', 'B', 'T', 'Q']; let suffixIndex = 0; while (absNumber >= 1000 && suffixIndex < suffixes.length - 1) { absNumber /= 1000; suffixIndex++; } let shortNumber = parseFloat(absNumber.toFixed(2)); return (number < 0 ? '-' : '') + shortNumber + ' ' + suffixes[suffixIndex]; } function formatDate(dateString) { const inputDate = new Date(dateString); const days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', ]; const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ]; const dayOfWeek = days[inputDate.getDay()]; const month = months[inputDate.getMonth()]; const day = inputDate.getDate(); const year = inputDate.getFullYear(); const formattedDate = dayOfWeek + ', ' + month + ' ' + day + ', ' + year; return formattedDate; } function formatCustomDate(inputDate) { var date = new Date(inputDate); // Array of month names var monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ]; // Get month and day var month = monthNames[date.getMonth()]; var day = date.getDate(); // Create formatted date string in "MMM DD" format var formattedDate = month + ' ' + (day < 10 ? '0' + day : day); return formattedDate; } function shortenHex(address) { return `${address && address.substr(0, 6)}...${address.substr(-4)}`; } function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } function shortenToken(token) { return truncateString(token, 14, ''); } function shortenTokenSymbol(token) { return truncateString(token, 5, ''); } function gasPercentage(gasUsed, gasAttached) { if (!gasAttached) return 'N/A'; const formattedNumber = (Big(gasUsed).div(Big(gasAttached)) * 100).toFixed(2); return `${formattedNumber}%`; } function serialNumber(index, page, perPage) { return index + 1 + (page - 1) * perPage; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function localFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 5, }); return formattedNumber; } function dollarFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 2, maximumFractionDigits: 2, }); return formattedNumber; } function dollarNonCentFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 0, }); return formattedNumber; } function weight(number) { const suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; let suffixIndex = 0; while (number >= 1000 && suffixIndex < suffixes.length - 1) { number /= 1000; suffixIndex++; } return number.toFixed(2) + ' ' + suffixes[suffixIndex]; } function convertToUTC(timestamp, hour) { const date = new Date(timestamp); // Get UTC date components const utcYear = date.getUTCFullYear(); const utcMonth = ('0' + (date.getUTCMonth() + 1)).slice(-2); // Adding 1 because months are zero-based const utcDay = ('0' + date.getUTCDate()).slice(-2); const utcHours = ('0' + date.getUTCHours()).slice(-2); const utcMinutes = ('0' + date.getUTCMinutes()).slice(-2); const utcSeconds = ('0' + date.getUTCSeconds()).slice(-2); // Array of month abbreviations const monthAbbreviations = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ]; const monthIndex = Number(utcMonth) - 1; // Format the date as required (Jul-25-2022 16:25:37) let formattedDate = monthAbbreviations[monthIndex] + '-' + utcDay + '-' + utcYear + ' ' + utcHours + ':' + utcMinutes + ':' + utcSeconds; if (hour) { // Convert hours to 12-hour format let hour12 = parseInt(utcHours); const ampm = hour12 >= 12 ? 'PM' : 'AM'; hour12 = hour12 % 12 || 12; // Add AM/PM to the formatted date (Jul-25-2022 4:25:37 PM) formattedDate = monthAbbreviations[monthIndex] + '-' + utcDay + '-' + utcYear + ' ' + hour12 + ':' + utcMinutes + ':' + utcSeconds + ' ' + ampm; } return formattedDate; } function getTimeAgoString(timestamp) { const currentUTC = Date.now(); const date = new Date(timestamp); const seconds = Math.floor((currentUTC - date.getTime()) / 1000); const intervals = { year: seconds / (60 * 60 * 24 * 365), month: seconds / (60 * 60 * 24 * 30), week: seconds / (60 * 60 * 24 * 7), day: seconds / (60 * 60 * 24), hour: seconds / (60 * 60), minute: seconds / 60, }; if (intervals.year == 1) { return Math.ceil(intervals.year) + ' year ago'; } else if (intervals.year > 1) { return Math.ceil(intervals.year) + ' years ago'; } else if (intervals.month > 1) { return Math.ceil(intervals.month) + ' months ago'; } else if (intervals.week > 1) { return Math.ceil(intervals.week) + ' weeks ago'; } else if (intervals.day > 1) { return Math.ceil(intervals.day) + ' days ago'; } else if (intervals.hour > 1) { return Math.ceil(intervals.hour) + ' hours ago'; } else if (intervals.minute > 1) { return Math.ceil(intervals.minute) + ' minutes ago'; } else { return 'a few seconds ago'; } } function formatWithCommas(number) { return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } function formatTimestampToString(timestamp) { const date = new Date(timestamp); // Format the date to 'YYYY-MM-DD HH:mm:ss' format const formattedDate = date.toISOString().replace('T', ' ').split('.')[0]; return formattedDate; } function convertToMetricPrefix(number) { const prefixes = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']; // Metric prefixes let count = 0; while (Math.abs(number) >= 1000 && count < prefixes.length - 1) { number /= 1000; count++; } // Check if the number is close to an integer value if (Math.abs(number) >= 10) { number = Math.round(number); // Round the number to the nearest whole number return number + ' ' + prefixes[count]; } return ( Number(Math.floor(number * 100) / 100).toFixed(2) + ' ' + prefixes[count] ); } function formatNumber(value) { const suffixes = ['', 'K', 'M', 'B', 'T']; let suffixIndex = 0; while (value >= 10000 && suffixIndex < suffixes.length - 1) { value /= 1000; suffixIndex++; } const formattedValue = value.toFixed(1).replace(/\.0+$/, ''); return `${formattedValue} ${suffixes[suffixIndex]}`; } function gasFee(gas, price) { const near = yoctoToNear(Big(gas).mul(Big(price)).toString(), true); return `${near} Ⓝ`; } function currency(number) { let absNumber = Math.abs(number); const suffixes = ['', 'K', 'M', 'B', 'T', 'Q']; let suffixIndex = 0; while (absNumber >= 1000 && suffixIndex < suffixes.length - 1) { absNumber /= 1000; suffixIndex++; } let shortNumber = parseFloat(absNumber.toFixed(2)); return (number < 0 ? '-' : '') + shortNumber + ' ' + suffixes[suffixIndex]; } function formatDate(dateString) { const inputDate = new Date(dateString); const days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', ]; const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ]; const dayOfWeek = days[inputDate.getDay()]; const month = months[inputDate.getMonth()]; const day = inputDate.getDate(); const year = inputDate.getFullYear(); const formattedDate = dayOfWeek + ', ' + month + ' ' + day + ', ' + year; return formattedDate; } function formatCustomDate(inputDate) { var date = new Date(inputDate); // Array of month names var monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ]; // Get month and day var month = monthNames[date.getMonth()]; var day = date.getDate(); // Create formatted date string in "MMM DD" format var formattedDate = month + ' ' + (day < 10 ? '0' + day : day); return formattedDate; } function shortenHex(address) { return `${address && address.substr(0, 6)}...${address.substr(-4)}`; } function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } function shortenToken(token) { return truncateString(token, 14, ''); } function shortenTokenSymbol(token) { return truncateString(token, 5, ''); } function gasPercentage(gasUsed, gasAttached) { if (!gasAttached) return 'N/A'; const formattedNumber = (Big(gasUsed).div(Big(gasAttached)) * 100).toFixed(2); return `${formattedNumber}%`; } function serialNumber(index, page, perPage) { return index + 1 + (page - 1) * perPage; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } /* END_INCLUDE: "includes/formats.jsx" */ /* INCLUDE: "includes/libs.jsx" */ function getConfig(network) { switch (network) { case 'mainnet': return { ownerId: 'nearblocks.near', nodeUrl: 'https://rpc.mainnet.near.org', backendUrl: 'https://api3.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://nearblocks.io/', }; case 'testnet': return { ownerId: 'nearblocks.testnet', nodeUrl: 'https://rpc.testnet.near.org', backendUrl: 'https://api3-testnet.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://testnet.nearblocks.io/', }; default: return {}; } } function debounce( delay, func, ) { let timer; let active = true; const debounced = (arg) => { if (active) { clearTimeout(timer); timer = setTimeout(() => { active && func(arg); timer = undefined; }, delay); } else { func(arg); } }; debounced.isPending = () => { return timer !== undefined; }; debounced.cancel = () => { active = false; }; debounced.flush = (arg) => func(arg); return debounced; } function timeAgo(unixTimestamp) { const currentTimestamp = Math.floor(Date.now() / 1000); const secondsAgo = currentTimestamp - unixTimestamp; if (secondsAgo < 5) { return 'Just now'; } else if (secondsAgo < 60) { return `${secondsAgo} seconds ago`; } else if (secondsAgo < 3600) { const minutesAgo = Math.floor(secondsAgo / 60); return `${minutesAgo} minute${minutesAgo > 1 ? 's' : ''} ago`; } else if (secondsAgo < 86400) { const hoursAgo = Math.floor(secondsAgo / 3600); return `${hoursAgo} hour${hoursAgo > 1 ? 's' : ''} ago`; } else { const daysAgo = Math.floor(secondsAgo / 86400); return `${daysAgo} day${daysAgo > 1 ? 's' : ''} ago`; } } function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function fiatValue(big, price) { // @ts-ignore const value = Big(big).mul(Big(price)).toString(); const formattedNumber = Number(value).toLocaleString('en', { minimumFractionDigits: 2, maximumFractionDigits: 6, }); return formattedNumber; } function nanoToMilli(nano) { return new Big(nano).div(new Big(10).pow(6)).round().toNumber(); } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function getConfig(network) { switch (network) { case 'mainnet': return { ownerId: 'nearblocks.near', nodeUrl: 'https://rpc.mainnet.near.org', backendUrl: 'https://api3.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://nearblocks.io/', }; case 'testnet': return { ownerId: 'nearblocks.testnet', nodeUrl: 'https://rpc.testnet.near.org', backendUrl: 'https://api3-testnet.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://testnet.nearblocks.io/', }; default: return {}; } } function debounce( delay, func, ) { let timer; let active = true; const debounced = (arg) => { if (active) { clearTimeout(timer); timer = setTimeout(() => { active && func(arg); timer = undefined; }, delay); } else { func(arg); } }; debounced.isPending = () => { return timer !== undefined; }; debounced.cancel = () => { active = false; }; debounced.flush = (arg) => func(arg); return debounced; } function timeAgo(unixTimestamp) { const currentTimestamp = Math.floor(Date.now() / 1000); const secondsAgo = currentTimestamp - unixTimestamp; if (secondsAgo < 5) { return 'Just now'; } else if (secondsAgo < 60) { return `${secondsAgo} seconds ago`; } else if (secondsAgo < 3600) { const minutesAgo = Math.floor(secondsAgo / 60); return `${minutesAgo} minute${minutesAgo > 1 ? 's' : ''} ago`; } else if (secondsAgo < 86400) { const hoursAgo = Math.floor(secondsAgo / 3600); return `${hoursAgo} hour${hoursAgo > 1 ? 's' : ''} ago`; } else { const daysAgo = Math.floor(secondsAgo / 86400); return `${daysAgo} day${daysAgo > 1 ? 's' : ''} ago`; } } function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } function localFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 5, }); return formattedNumber; } function formatWithCommas(number) { return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } /* END_INCLUDE: "includes/libs.jsx" */ /* INCLUDE COMPONENT: "includes/Common/Receipts/ReceiptStatus.jsx" */ /* INCLUDE: "includes/near.jsx" */ function formatLine(line, offset, format) { let result = `${offset.toString(16).padStart(8, '0')} `; const bytes = line.split(' ').filter(Boolean); bytes.forEach((byte, index) => { if (index > 0 && index % 4 === 0) { result += ' '; } result += byte.toUpperCase().padEnd(2, ' ') + ' '; }); if (format === 'default') { result += ` ${String.fromCharCode( ...bytes.map((b) => parseInt(b, 16)), )}`; } return result.trimEnd(); } /* END_INCLUDE: "includes/near.jsx" */ const ReceiptStatus = (props) => { const { receipt } = props; function hexDump( data, options , ) { const { width = 16, format = 'default' } = options; let result = ''; let line = ''; for (let i = 0; i < data.length; i++) { if (i > 0 && i % width === 0) { result += formatLine(line, i - width, format) + '\n'; line = ''; } const byte = data[i]; line += byte.toString(16).padStart(2, '0') + ' '; } if (line.length > 0) { result += formatLine(line, data.length - (data.length % width), format) + '\n'; } return result; } function displayArgs(args) { if (!args || typeof args === 'undefined') return 'The arguments are empty'; let pretty = ''; const decoded = Buffer.from(args, 'base64'); try { const parsed = JSON.parse(decoded.toString()); pretty = JSON.stringify(parsed, null, 2); } catch { pretty = hexDump(decoded, { format: 'twos' }); } return pretty; } const status = receipt.outcome.status; if (status && 'SuccessValue' in status) { const { SuccessValue } = status; if (SuccessValue === null || SuccessValue === undefined) { return 'No Result'; } if (Array.isArray(SuccessValue) || typeof SuccessValue === 'string') { if (SuccessValue.length === 0) { return 'Empty Result'; } } return ( <textarea readOnly rows={4} defaultValue={displayArgs(SuccessValue)} className="block appearance-none outline-none w-full border rounded-lg bg-gray-100 p-3 mt-3 resize-y" ></textarea> ); } if (status && 'Failure' in status) { return ( <textarea readOnly rows={4} defaultValue={JSON.stringify(status.Failure, null, 2)} className="block appearance-none outline-none w-full border rounded-lg bg-gray-100 p-3 mt-3 resize-y" ></textarea> ); } if (status && 'SuccessReceiptId' in status) { return status.SuccessReceiptId; } return ''; };/* END_INCLUDE COMPONENT: "includes/Common/Receipts/ReceiptStatus.jsx" */ /* INCLUDE COMPONENT: "includes/Common/Receipts/TransactionActions.jsx" */ /* INCLUDE: "includes/formats.jsx" */ function shortenHex(address) { return `${address && address.substr(0, 6)}...${address.substr(-4)}`; } function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } function shortenToken(token) { return truncateString(token, 14, ''); } function shortenTokenSymbol(token) { return truncateString(token, 5, ''); } function gasPercentage(gasUsed, gasAttached) { if (!gasAttached) return 'N/A'; const formattedNumber = (Big(gasUsed).div(Big(gasAttached)) * 100).toFixed(2); return `${formattedNumber}%`; } function serialNumber(index, page, perPage) { return index + 1 + (page - 1) * perPage; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } /* END_INCLUDE: "includes/formats.jsx" */ /** * @interface Props * @param {string} [className] - The CSS class name(s) for styling purposes. */ const FaKey = (props) => { return ( <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" className={props.className} height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" > <path d="M512 176.001C512 273.203 433.202 352 336 352c-11.22 0-22.19-1.062-32.827-3.069l-24.012 27.014A23.999 23.999 0 0 1 261.223 384H224v40c0 13.255-10.745 24-24 24h-40v40c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24v-78.059c0-6.365 2.529-12.47 7.029-16.971l161.802-161.802C163.108 213.814 160 195.271 160 176 160 78.798 238.797.001 335.999 0 433.488-.001 512 78.511 512 176.001zM336 128c0 26.51 21.49 48 48 48s48-21.49 48-48-21.49-48-48-48-48 21.49-48 48z"></path> </svg> ); }; /* INCLUDE: "includes/libs.jsx" */ function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } /* END_INCLUDE: "includes/libs.jsx" */ const AddKey = (props) => { if (typeof props.args.access_key?.permission !== 'object') { return ( <div className="py-1"> <FaKey className="inline-flex text-emerald-400 mr-1" />{' '} {props.t ? props.t('txns:txn.actions.addKey.0') : 'New key'} ( <span className="font-bold">{shortenHex(props.args.public_key)}</span>){' '} {props.t ? props.t('txns:txn.actions.addKey.2') : 'added for'} <a href={`/address/${props.receiver}`} className="hover:no-underline"> <a className="text-green-500 font-bold hover:no-underline"> {shortenAddress(props.receiver)} </a> </a>{' '} {props.t ? props.t('txns:txn.actions.addKey.4') : 'with permission'} <span className="font-bold">{props.args.access_key?.permission}</span> </div> ); } if (props.args.access_key.permission.permission_kind) { return ( <div className="py-1"> <FaKey className="inline-flex text-gray-400 mr-1" />{' '} {props.t ? props.t('txns:txn.actions.addKey.0') : 'New key'} ( <span className="font-bold">{shortenHex(props.args.public_key)}</span>) {props.t ? props.t('txns:txn.actions.addKey.2') : 'added for'}{' '} <a href={`/address/${props.receiver}`} className="hover:no-underline"> <a className="text-green-500 font-bold hover:no-underline"> {shortenAddress(props.receiver)} </a> </a>{' '} {props.t ? props.t('txns:txn.actions.addKey.4') : 'with permission'}{' '} <span className="font-bold"> {props.args.access_key.permission.permission_kind} </span> </div> ); } return ( <div className="py-1"> <FaKey className="inline-flex text-gray-400 mr-1" />{' '} {props.t ? props.t('txns:txn.actions.addKey.1') : 'Access key'} ( <span className="font-bold">{shortenHex(props.args.public_key)}</span>){' '} {props.t ? props.t('txns:txn.actions.addKey.2') : 'added for'} {props.t ? props.t('txns:txn.actions.addKey.3') : 'contract'} <a href={`/address/${props.args.access_key.permission.FunctionCall.receiver_id}`} className="hover:no-underline" > <a className="text-green-500 font-bold hover:no-underline"> {shortenAddress( props.args.access_key.permission.FunctionCall.receiver_id, )} </a> </a>{' '} {props.t ? props.t('txns:txn.actions.addKey.4') : 'with permission'} {props.t ? props.t('txns:txn.actions.addKey.5') : 'to call'} <span className="font-bold"> {props.args.access_key.permission.FunctionCall.method_names.length > 0 ? props.args.access_key.permission.FunctionCall.method_names.join( ', ', ) : 'any'}{' '} </span> {props.t ? props.t('txns:txn.actions.addKey.6') : 'methods'} </div> ); }; /** * @interface Props * @param {string} [className] - The CSS class name(s) for styling purposes. */ const FaUser = (props) => { return ( <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 448 512" className={props.className} height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" > <path d="M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-74.2-60.2-134.4-134.4-134.4z"></path> </svg> ); }; /* INCLUDE: "includes/libs.jsx" */ function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } /* END_INCLUDE: "includes/libs.jsx" */ const CreateAccount = (props) => { return ( <div className="py-1"> <FaUser className="inline-flex text-emerald-400 mr-1" />{' '} {props.t ? props.t('txns:txn.actions.createAccount.0') : 'New account'} ( <a href={`/address/${props.receiver}`} className="hover:no-underline"> <a className="text-green-500 font-bold hover:no-underline"> {shortenAddress(props.receiver)} </a> </a> ) {props.t ? props.t('txns:txn.actions.createAccount.1') : 'created'} </div> ); }; /* INCLUDE: "includes/libs.jsx" */ function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } /* END_INCLUDE: "includes/libs.jsx" */ const DeleteAccount = (props) => { return ( <div className="py-1"> <FaUser className="inline-flex text-red-400 mr-1" /> {props.t ? props.t('txns:txn.actions.deleteAccount.0') : 'Delete account'}{' '} ( <a href={`/address/${props.receiver}`} className="hover:no-underline"> <a className="text-green-500 font-bold hover:no-underline"> {shortenAddress(props.receiver)} </a> </a> ){' '} {props.t ? props.t('txns:txn.actions.deleteAccount.1') : 'and transfer remaining funds to'} <a href={`/address/${props.args.beneficiary_id}`} className="hover:no-underline" > <a className="text-green-500 font-bold hover:no-underline"> {shortenAddress(props.args.beneficiary_id)} </a> </a> </div> ); }; /* INCLUDE: "includes/formats.jsx" */ function shortenHex(address) { return `${address && address.substr(0, 6)}...${address.substr(-4)}`; } function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } function shortenToken(token) { return truncateString(token, 14, ''); } function shortenTokenSymbol(token) { return truncateString(token, 5, ''); } function gasPercentage(gasUsed, gasAttached) { if (!gasAttached) return 'N/A'; const formattedNumber = (Big(gasUsed).div(Big(gasAttached)) * 100).toFixed(2); return `${formattedNumber}%`; } function serialNumber(index, page, perPage) { return index + 1 + (page - 1) * perPage; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } /* END_INCLUDE: "includes/formats.jsx" */ const DeleteKey = (props) => { const { t, args } = props; return ( <div className="py-1"> <FaKey className="inline-flex text-red-400 mr-1" />{' '} {t ? t('txns:txn.actions.deleteKey.0') : 'Key'} ( <span className="font-bold">{shortenHex(args.public_key)}</span>){' '} {t ? t('txns:txn.actions.deleteKey.1') : 'deleted'} </div> ); }; /** * @interface Props * @param {string} [className] - The CSS class name(s) for styling purposes. */ const FaCode = (props) => { return ( <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 640 512" className={props.className} height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" > <path d="M278.9 511.5l-61-17.7c-6.4-1.8-10-8.5-8.2-14.9L346.2 8.7c1.8-6.4 8.5-10 14.9-8.2l61 17.7c6.4 1.8 10 8.5 8.2 14.9L293.8 503.3c-1.9 6.4-8.5 10.1-14.9 8.2zm-114-112.2l43.5-46.4c4.6-4.9 4.3-12.7-.8-17.2L117 256l90.6-79.7c5.1-4.5 5.5-12.3.8-17.2l-43.5-46.4c-4.5-4.8-12.1-5.1-17-.5L3.8 247.2c-5.1 4.7-5.1 12.8 0 17.5l144.1 135.1c4.9 4.6 12.5 4.4 17-.5zm327.2.6l144.1-135.1c5.1-4.7 5.1-12.8 0-17.5L492.1 112.1c-4.8-4.5-12.4-4.3-17 .5L431.6 159c-4.6 4.9-4.3 12.7.8 17.2L523 256l-90.6 79.7c-5.1 4.5-5.5 12.3-.8 17.2l43.5 46.4c4.5 4.9 12.1 5.1 17 .6z"></path> </svg> ); }; /* INCLUDE: "includes/libs.jsx" */ function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } /* END_INCLUDE: "includes/libs.jsx" */ const DeployContract = (props) => { const { t, receiver } = props; return ( <div className="py-1"> <FaCode className="inline-flex text-emerald-400 mr-1" />{' '} {t ? t('txns:txn.actions.deployContract.0') : 'Contract'} ( <a href={`/address/${receiver}`} className="hover:no-underline"> <a className="text-green-500 font-bold hover:no-underline"> {shortenAddress(receiver)} </a> </a> ) {t ? t('txns:txn.actions.deployContract.1') : 'deployed'} </div> ); }; /* INCLUDE: "includes/libs.jsx" */ function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } /* END_INCLUDE: "includes/libs.jsx" */ /* INCLUDE: "includes/near.jsx" */ function formatLine(line, offset, format) { let result = `${offset.toString(16).padStart(8, '0')} `; const bytes = line.split(' ').filter(Boolean); bytes.forEach((byte, index) => { if (index > 0 && index % 4 === 0) { result += ' '; } result += byte.toUpperCase().padEnd(2, ' ') + ' '; }); if (format === 'default') { result += ` ${String.fromCharCode( ...bytes.map((b) => parseInt(b, 16)), )}`; } return result.trimEnd(); } /* END_INCLUDE: "includes/near.jsx" */ const FunctionCall = (props) => { const { t, args, receiver } = props; function hexDump( data, options , ) { const { width = 16, format = 'default' } = options; let result = ''; let line = ''; for (let i = 0; i < data.length; i++) { if (i > 0 && i % width === 0) { result += formatLine(line, i - width, format) + '\n'; line = ''; } const byte = data[i]; line += byte.toString(16).padStart(2, '0') + ' '; } if (line.length > 0) { result += formatLine(line, data.length - (data.length % width), format) + '\n'; } return result; } function displayArgs(args) { if (!args || typeof args === 'undefined') return 'The arguments are empty'; let pretty = ''; const decoded = Buffer.from(args, 'base64'); try { const parsed = JSON.parse(decoded.toString()); pretty = JSON.stringify(parsed, null, 2); } catch { pretty = hexDump(decoded, { format: 'twos' }); } return pretty; } return ( <div className="py-1"> <FaCode className="inline-flex text-yellow-500 mr-1" /> {t ? t('txns:txn.actions.functionCall.0') : 'Called method'} <span className="font-bold">{args.method_name}</span>{' '} {t ? t('txns:txn.actions.functionCall.1') : 'in contract'} <a href={`/address/${receiver}`} className="hover:no-underline"> <a className="text-green-500 font-bold hover:no-underline"> {shortenAddress(receiver)} </a> </a> <textarea readOnly rows={4} defaultValue={displayArgs(args.args_base64 || args.args)} className="block appearance-none outline-none w-full border rounded-lg bg-gray-100 p-3 mt-3 resize-y" ></textarea> </div> ); }; /* INCLUDE: "includes/formats.jsx" */ function shortenHex(address) { return `${address && address.substr(0, 6)}...${address.substr(-4)}`; } function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } function shortenToken(token) { return truncateString(token, 14, ''); } function shortenTokenSymbol(token) { return truncateString(token, 5, ''); } function gasPercentage(gasUsed, gasAttached) { if (!gasAttached) return 'N/A'; const formattedNumber = (Big(gasUsed).div(Big(gasAttached)) * 100).toFixed(2); return `${formattedNumber}%`; } function serialNumber(index, page, perPage) { return index + 1 + (page - 1) * perPage; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } /* END_INCLUDE: "includes/formats.jsx" */ /** * @interface Props * @param {string} [className] - The CSS class name(s) for styling purposes. */ const FaCoins = (props) => { return ( <svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512" {...props} > <path fill="#eab308" d="M512 80c0 18-14.3 34.6-38.4 48c-29.1 16.1-72.5 27.5-122.3 30.9c-3.7-1.8-7.4-3.5-11.3-5C300.6 137.4 248.2 128 192 128c-8.3 0-16.4 .2-24.5 .6l-1.1-.6C142.3 114.6 128 98 128 80c0-44.2 86-80 192-80S512 35.8 512 80zM160.7 161.1c10.2-.7 20.7-1.1 31.3-1.1c62.2 0 117.4 12.3 152.5 31.4C369.3 204.9 384 221.7 384 240c0 4-.7 7.9-2.1 11.7c-4.6 13.2-17 25.3-35 35.5c0 0 0 0 0 0c-.1 .1-.3 .1-.4 .2l0 0 0 0c-.3 .2-.6 .3-.9 .5c-35 19.4-90.8 32-153.6 32c-59.6 0-112.9-11.3-148.2-29.1c-1.9-.9-3.7-1.9-5.5-2.9C14.3 274.6 0 258 0 240c0-34.8 53.4-64.5 128-75.4c10.5-1.5 21.4-2.7 32.7-3.5zM416 240c0-21.9-10.6-39.9-24.1-53.4c28.3-4.4 54.2-11.4 76.2-20.5c16.3-6.8 31.5-15.2 43.9-25.5V176c0 19.3-16.5 37.1-43.8 50.9c-14.6 7.4-32.4 13.7-52.4 18.5c.1-1.8 .2-3.5 .2-5.3zm-32 96c0 18-14.3 34.6-38.4 48c-1.8 1-3.6 1.9-5.5 2.9C304.9 404.7 251.6 416 192 416c-62.8 0-118.6-12.6-153.6-32C14.3 370.6 0 354 0 336V300.6c12.5 10.3 27.6 18.7 43.9 25.5C83.4 342.6 135.8 352 192 352s108.6-9.4 148.1-25.9c7.8-3.2 15.3-6.9 22.4-10.9c6.1-3.4 11.8-7.2 17.2-11.2c1.5-1.1 2.9-2.3 4.3-3.4V304v5.7V336zm32 0V304 278.1c19-4.2 36.5-9.5 52.1-16c16.3-6.8 31.5-15.2 43.9-25.5V272c0 10.5-5 21-14.9 30.9c-16.3 16.3-45 29.7-81.3 38.4c.1-1.7 .2-3.5 .2-5.3zM192 448c56.2 0 108.6-9.4 148.1-25.9c16.3-6.8 31.5-15.2 43.9-25.5V432c0 44.2-86 80-192 80S0 476.2 0 432V396.6c12.5 10.3 27.6 18.7 43.9 25.5C83.4 438.6 135.8 448 192 448z" /> </svg> ); }; /* INCLUDE: "includes/libs.jsx" */ function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function fiatValue(big, price) { // @ts-ignore const value = Big(big).mul(Big(price)).toString(); const formattedNumber = Number(value).toLocaleString('en', { minimumFractionDigits: 2, maximumFractionDigits: 6, }); return formattedNumber; } function nanoToMilli(nano) { return new Big(nano).div(new Big(10).pow(6)).round().toNumber(); } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function getConfig(network) { switch (network) { case 'mainnet': return { ownerId: 'nearblocks.near', nodeUrl: 'https://rpc.mainnet.near.org', backendUrl: 'https://api3.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://nearblocks.io/', }; case 'testnet': return { ownerId: 'nearblocks.testnet', nodeUrl: 'https://rpc.testnet.near.org', backendUrl: 'https://api3-testnet.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://testnet.nearblocks.io/', }; default: return {}; } } function debounce( delay, func, ) { let timer; let active = true; const debounced = (arg) => { if (active) { clearTimeout(timer); timer = setTimeout(() => { active && func(arg); timer = undefined; }, delay); } else { func(arg); } }; debounced.isPending = () => { return timer !== undefined; }; debounced.cancel = () => { active = false; }; debounced.flush = (arg) => func(arg); return debounced; } function timeAgo(unixTimestamp) { const currentTimestamp = Math.floor(Date.now() / 1000); const secondsAgo = currentTimestamp - unixTimestamp; if (secondsAgo < 5) { return 'Just now'; } else if (secondsAgo < 60) { return `${secondsAgo} seconds ago`; } else if (secondsAgo < 3600) { const minutesAgo = Math.floor(secondsAgo / 60); return `${minutesAgo} minute${minutesAgo > 1 ? 's' : ''} ago`; } else if (secondsAgo < 86400) { const hoursAgo = Math.floor(secondsAgo / 3600); return `${hoursAgo} hour${hoursAgo > 1 ? 's' : ''} ago`; } else { const daysAgo = Math.floor(secondsAgo / 86400); return `${daysAgo} day${daysAgo > 1 ? 's' : ''} ago`; } } function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } function localFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 5, }); return formattedNumber; } function formatWithCommas(number) { return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } /* END_INCLUDE: "includes/libs.jsx" */ const Stake = (props) => { const { t, args } = props; return ( <div className="py-1"> <FaCoins className="inline-flex text-yellow-500 mr-1" /> {t ? t('txns:txn.actions.stake.0') : 'Staked'} <span className="font-bold">{yoctoToNear(args.stake, true)} Ⓝ</span>{' '} {t ? t('txns:txn.actions.stake.1') : 'with'} {shortenHex(args.public_key)} </div> ); }; /** * @interface Props * @param {string} [className] - The CSS class name(s) for styling purposes. */ const FaArrowAltCircleRight = (props) => { return ( <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" className={props.className} height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" > <path d="M256 8c137 0 248 111 248 248S393 504 256 504 8 393 8 256 119 8 256 8zM140 300h116v70.9c0 10.7 13 16.1 20.5 8.5l114.3-114.9c4.7-4.7 4.7-12.2 0-16.9l-114.3-115c-7.6-7.6-20.5-2.2-20.5 8.5V212H140c-6.6 0-12 5.4-12 12v64c0 6.6 5.4 12 12 12z"></path> </svg> ); }; /* INCLUDE: "includes/libs.jsx" */ function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function fiatValue(big, price) { // @ts-ignore const value = Big(big).mul(Big(price)).toString(); const formattedNumber = Number(value).toLocaleString('en', { minimumFractionDigits: 2, maximumFractionDigits: 6, }); return formattedNumber; } function nanoToMilli(nano) { return new Big(nano).div(new Big(10).pow(6)).round().toNumber(); } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function getConfig(network) { switch (network) { case 'mainnet': return { ownerId: 'nearblocks.near', nodeUrl: 'https://rpc.mainnet.near.org', backendUrl: 'https://api3.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://nearblocks.io/', }; case 'testnet': return { ownerId: 'nearblocks.testnet', nodeUrl: 'https://rpc.testnet.near.org', backendUrl: 'https://api3-testnet.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://testnet.nearblocks.io/', }; default: return {}; } } function debounce( delay, func, ) { let timer; let active = true; const debounced = (arg) => { if (active) { clearTimeout(timer); timer = setTimeout(() => { active && func(arg); timer = undefined; }, delay); } else { func(arg); } }; debounced.isPending = () => { return timer !== undefined; }; debounced.cancel = () => { active = false; }; debounced.flush = (arg) => func(arg); return debounced; } function timeAgo(unixTimestamp) { const currentTimestamp = Math.floor(Date.now() / 1000); const secondsAgo = currentTimestamp - unixTimestamp; if (secondsAgo < 5) { return 'Just now'; } else if (secondsAgo < 60) { return `${secondsAgo} seconds ago`; } else if (secondsAgo < 3600) { const minutesAgo = Math.floor(secondsAgo / 60); return `${minutesAgo} minute${minutesAgo > 1 ? 's' : ''} ago`; } else if (secondsAgo < 86400) { const hoursAgo = Math.floor(secondsAgo / 3600); return `${hoursAgo} hour${hoursAgo > 1 ? 's' : ''} ago`; } else { const daysAgo = Math.floor(secondsAgo / 86400); return `${daysAgo} day${daysAgo > 1 ? 's' : ''} ago`; } } function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } function localFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 5, }); return formattedNumber; } function formatWithCommas(number) { return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } /* END_INCLUDE: "includes/libs.jsx" */ const Transfer = (props) => { const { t, args, receiver } = props; return ( <div className="py-1"> <FaArrowAltCircleRight className="inline-flex text-green-400 mr-1" />{' '} {t ? t('txns:txn.actions.transfer.0') : 'Transferred'} <span className="font-bold"> {yoctoToNear(args.deposit, true)} Ⓝ </span>{' '} {t ? t('txns:txn.actions.transfer.1') : 'to'} <a href={`/address/${receiver}`} className="hover:no-underline"> <a className="text-green-500 font-bold hover:no-underline"> {shortenAddress(receiver)} </a> </a> </div> ); }; const TransactionActions = (props) => { const { action, receiver, t } = props; switch (action.action_kind) { case 'ADD_KEY': case 'AddKey': return <AddKey args={action.args} receiver={receiver} t={t} />; case 'CREATE_ACCOUNT': case 'CreateAccount': return <CreateAccount args={action.args} receiver={receiver} t={t} />; case 'DELETE_ACCOUNT': case 'DeleteAccount': return <DeleteAccount args={action.args} receiver={receiver} t={t} />; case 'DELETE_KEY': case 'DeleteKey': return <DeleteKey args={action.args} receiver={receiver} t={t} />; case 'DEPLOY_CONTRACT': case 'DeployContract': return <DeployContract args={action.args} receiver={receiver} t={t} />; case 'FUNCTION_CALL': case 'FunctionCall': return <FunctionCall args={action.args} receiver={receiver} t={t} />; case 'STAKE': case 'Stake': return <Stake args={action.args} receiver={receiver} t={t} />; case 'TRANSFER': case 'Transfer': return <Transfer args={action.args} receiver={receiver} t={t} />; default: return <div>{action.action_kind}</div>; } };/* END_INCLUDE COMPONENT: "includes/Common/Receipts/TransactionActions.jsx" */ function MainComponent(props) { const { network, receipt, borderFlag, t } = props; const [block, setBlock] = useState({} ); const [loading, setLoading] = useState(false); const config = getConfig(network); useEffect(() => { function fetchBlocks() { setLoading(true); if (receipt?.block_hash) { asyncFetch(`${config.backendUrl}blocks/${receipt?.block_hash}`) .then( (res ) => { const resp = res?.body?.blocks?.[0]; if (res.status === 200) { setBlock({ author_account_id: resp.author_account_id, block_hash: resp.author_account_id, block_height: resp.block_height, block_timestamp: resp.block_timestamp, chunks_agg: resp.chunks_agg, gas_price: resp.gas_price, prev_block_hash: resp.author_account_id, receipts_agg: resp.receipts_agg, transactions_agg: resp.transactions_agg, }); } }, ) .catch(() => {}); } setLoading(false); } fetchBlocks(); }, [receipt?.block_hash, config.backendUrl]); const Loader = (props) => { return ( <div className={`bg-gray-200 h-5 rounded shadow-sm animate-pulse ${props.className}`} ></div> ); }; return ( <div className="divide-solid divide-gray-200 divide-y"> <div className={borderFlag ? '' : 'border-l-4 border-green-400 ml-8 my-2'} > <div className="flex flex-wrap p-4"> <div className="flex items-center w-full md:w-1/4 mb-2 md:mb-0"> <Tooltip.Provider> <Tooltip.Root> <Tooltip.Trigger asChild> <div> <Question className="w-4 h-4 fill-current mr-1" /> </div> </Tooltip.Trigger> <Tooltip.Content className="h-auto max-w-xs bg-black bg-opacity-90 z-10 text-xs text-white px-3 py-2" align="start" side="bottom" > {t ? t('txns:txn.receipts.receipt.tooltip') : 'Unique identifier (hash) of this receipt.'} </Tooltip.Content> </Tooltip.Root> </Tooltip.Provider> {t ? t('txns:txn.receipts.receipt.text.0') : 'Receipt'} </div> {!receipt ? ( <div className="w-full md:w-3/4"> <Loader wrapperClassName="flex w-full max-w-xs" /> </div> ) : ( <div className="w-full md:w-3/4 font-semibold word-break"> {receipt.receipt_id ? receipt.receipt_id : ''} </div> )} </div> <div className="flex flex-wrap p-4"> <div className="flex items-center w-full md:w-1/4 mb-2 md:mb-0"> <Tooltip.Provider> <Tooltip.Root> <Tooltip.Trigger asChild> <div> <Question className="w-4 h-4 fill-current mr-1" /> </div> </Tooltip.Trigger> <Tooltip.Content className="h-auto max-w-xs bg-black bg-opacity-90 z-10 text-xs text-white px-3 py-2" align="start" side="bottom" > Block height </Tooltip.Content> </Tooltip.Root> </Tooltip.Provider> {t ? t('txns:txn.receipts.block.text.0') : 'Block'} </div> {!receipt || loading ? ( <div className="w-full md:w-3/4"> <Loader wrapperClassName="flex w-full max-w-xs" /> </div> ) : block?.block_height ? ( <div className="w-full md:w-3/4 word-break"> <a href={`/blocks/${receipt.block_hash}`} className="hover:no-underline" > <a className="text-green-500 hover:no-underline"> {localFormat(block?.block_height)} </a> </a> </div> ) : ( '' )} </div> <div> <div className="flex flex-wrap p-4"> <div className="flex items-center w-full md:w-1/4 mb-2 md:mb-0"> <Tooltip.Provider> <Tooltip.Root> <Tooltip.Trigger asChild> <div> <Question className="w-4 h-4 fill-current mr-1" /> </div> </Tooltip.Trigger> <Tooltip.Content className="h-auto max-w-xs bg-black bg-opacity-90 z-10 text-xs text-white px-3 py-2" align="start" side="bottom" > {t ? t('txns:txn.receipts.from.tooltip') : 'The account which issued a receipt.'} </Tooltip.Content> </Tooltip.Root> </Tooltip.Provider> {t ? t('txns:txn.receipts.from.text.0') : 'From'} </div> {!receipt ? ( <div className="w-full md:w-3/4"> <Loader wrapperClassName="flex w-full max-w-sm" /> </div> ) : receipt.predecessor_id ? ( <div className="w-full md:w-3/4 word-break"> <a href={`/address/${receipt.predecessor_id}`} className="hover:no-underline" > <a className="text-green-500 hover:no-underline"> {receipt.predecessor_id} </a> </a> </div> ) : ( '' )} </div> <div className="flex flex-wrap p-4"> <div className="flex items-center w-full md:w-1/4 mb-2 md:mb-0"> <Tooltip.Provider> <Tooltip.Root> <Tooltip.Trigger asChild> <div> <Question className="w-4 h-4 fill-current mr-1" /> </div> </Tooltip.Trigger> <Tooltip.Content className="h-auto max-w-xs bg-black bg-opacity-90 z-10 text-xs text-white px-3 py-2" align="start" side="bottom" > {t ? t('txns:txn.receipts.to.tooltip') : 'The destination account of the receipt.'} </Tooltip.Content> </Tooltip.Root> </Tooltip.Provider> {t ? t('txns:txn.receipts.to.text.0') : 'To'} </div> {!receipt ? ( <div className="w-full md:w-3/4"> <Loader wrapperClassName="flex w-full max-w-xs" /> </div> ) : receipt.receiver_id ? ( <div className="w-full md:w-3/4 word-break"> <a href={`/address/${receipt.receiver_id}`} className="hover:no-underline" > <a className="text-green-500 hover:no-underline"> {receipt.receiver_id} </a> </a> </div> ) : ( '' )} </div> </div> <div className="flex flex-wrap p-4"> <div className="flex items-center w-full md:w-1/4 mb-2 md:mb-0"> <Tooltip.Provider> <Tooltip.Root> <Tooltip.Trigger asChild> <div> <Question className="w-4 h-4 fill-current mr-1" /> </div> </Tooltip.Trigger> <Tooltip.Content className="h-auto max-w-xs bg-black bg-opacity-90 z-10 text-xs text-white px-3 py-2" align="start" side="bottom" > {t ? t('txns:txn.receipts.burnt.tooltip') : 'Total amount of Gas & Token burnt from this receipt.'} </Tooltip.Content> </Tooltip.Root> </Tooltip.Provider> {t ? t('txns:txn.receipts.burnt.text.0') : 'Burnt Gas & Tokens by Receipt'} </div> {!receipt ? ( <div className="w-full md:w-3/4"> <Loader wrapperClassName="flex w-36" /> </div> ) : receipt.outcome.gas_burnt ? ( <div className="w-full items-center text-xs flex md:w-3/4 break-words"> <div className="bg-orange-50 rounded-md px-2 py-1"> <span className="text-xs mr-2">🔥 </span> {convertToMetricPrefix(receipt.outcome.gas_burnt ?? 0)}gas{' '} <span className="text-gray-300 px-1">|</span>{' '} {yoctoToNear(receipt.outcome.tokens_burnt, true)} Ⓝ </div> </div> ) : ( '' )} </div> <div className="flex items-start flex-wrap p-4"> <div className="flex items-center w-full md:w-1/4 mb-2 md:mb-0"> <Tooltip.Provider> <Tooltip.Root> <Tooltip.Trigger asChild> <div> <Question className="w-4 h-4 fill-current mr-1" /> </div> </Tooltip.Trigger> <Tooltip.Content className="h-auto max-w-xs bg-black bg-opacity-90 z-10 text-xs text-white px-3 py-2" align="start" side="bottom" > {t ? t('txns:txn.receipts.actions.tooltip') : 'The actions performed during receipt processing.'} </Tooltip.Content> </Tooltip.Root> </Tooltip.Provider> {t ? t('txns:txn.receipts.actions.text.0') : 'Actions'} </div> {!receipt ? ( <div className="w-full md:w-3/4"> <Loader wrapperClassName="flex w-full my-1 max-w-xs" /> <Loader wrapperClassName="flex w-full" /> <Loader wrapperClassName="flex w-full" /> <Loader wrapperClassName="flex w-full" /> </div> ) : receipt?.actions ? ( <div className="w-full md:w-3/4 word-break space-y-4"> {receipt?.actions?.map((action, i) => ( <TransactionActions key={i} action={action} receiver={receipt.receiver_id} t={t} /> ))} </div> ) : ( '' )} </div> <div className="flex items-start flex-wrap p-4"> <div className="flex items-center w-full md:w-1/4 mb-2 md:mb-0"> <Tooltip.Provider> <Tooltip.Root> <Tooltip.Trigger asChild> <div> <Question className="w-4 h-4 fill-current mr-1" /> </div> </Tooltip.Trigger> <Tooltip.Content className="h-auto max-w-xs bg-black bg-opacity-90 z-10 text-xs text-white px-3 py-2" align="start" side="bottom" > {t ? t('txns:txn.receipts.result.tooltip') : 'The result of the receipt execution.'} </Tooltip.Content> </Tooltip.Root> </Tooltip.Provider> {t ? t('txns:txn.receipts.result.text.0') : 'Result'} </div> {!receipt ? ( <div className="w-full md:w-3/4"> <Loader wrapperClassName="flex w-full" /> <Loader wrapperClassName="flex w-full" /> <Loader wrapperClassName="flex w-full" /> </div> ) : ( <div className="w-full md:w-3/4 break-words space-y-4"> {receipt ? <ReceiptStatus receipt={receipt} /> : ''} </div> )} </div> <div className="flex items-start flex-wrap p-4"> <div className="flex items-center w-full md:w-1/4 mb-2 md:mb-0"> <Tooltip.Provider> <Tooltip.Root> <Tooltip.Trigger asChild> <div> <Question className="w-4 h-4 fill-current mr-1" /> </div> </Tooltip.Trigger> <Tooltip.Content className="h-auto max-w-xs bg-black bg-opacity-90 z-10 text-xs text-white px-3 py-2" align="start" side="bottom" > {t ? t('txns:txn.receipts.logs.tooltip') : 'Logs included in the receipt.'} </Tooltip.Content> </Tooltip.Root> </Tooltip.Provider> {t ? t('txns:txn.receipts.logs.text.0') : 'Logs'} </div> {!receipt ? ( <div className="w-full md:w-3/4"> <Loader wrapperClassName="flex w-full" /> <Loader wrapperClassName="flex w-full" /> <Loader wrapperClassName="flex w-full" /> </div> ) : ( <div className="w-full md:w-3/4 break-words space-y-4"> {receipt?.outcome?.logs?.length > 0 ? ( <textarea readOnly rows={4} defaultValue={receipt.outcome.logs.join('\n')} className="block appearance-none outline-none w-full border rounded-lg bg-gray-100 p-3 mt-3 resize-y" ></textarea> ) : ( 'No Logs' )} </div> )} </div> </div> {receipt?.outcome?.outgoing_receipts?.length > 0 && ( <div className="pb-4"> {receipt.outcome.outgoing_receipts.map((rcpt) => ( <div className="pl-4 pt-6" key={rcpt.receipt_id}> <div className="mx-4 border-l-4 border-l-gray-200"> { <Widget src={`${config.ownerId}/widget/bos-components.components.Transactions.ReceiptRow`} props={{ receipt: rcpt, borderFlag: true, network: network, }} /> } </div> </div> ))} </div> )} </div> ); } return MainComponent(props, context);