Compare commits

...

14 Commits

Author SHA1 Message Date
a24616c03a
Merge pull request #8 from void-57/main
Some checks failed
Workflow push to Dappbundle / Build (push) Has been cancelled
fix: Update access token in push-dappbundle workflow for Git operations
2026-01-12 14:41:55 +05:30
8e8d4a9851 fix: Update access token in push-dappbundle workflow for Git operations 2026-01-12 14:40:17 +05:30
98bec90c82
Merge pull request #6 from void-57/main
fix: Update access token in push-dappbundle workflow for Git operations
2026-01-12 01:41:35 +05:30
f4ea9b43d6 fix: Update access token in push-dappbundle workflow for Git operations 2026-01-12 01:39:51 +05:30
05393be69b
Merge pull request #5 from void-57/main
refactor: Remove example usage code for balance fetching in bscOperator.js
2026-01-08 23:57:24 +05:30
1f1cc3c7e9 refactor: Remove example usage code for balance fetching in bscOperator.js 2026-01-08 23:54:36 +05:30
05eef4c4a2
Merge pull request #4 from void-57/main
fix: Update transaction input selectors to use form references
2026-01-08 22:23:51 +05:30
63257d7045 fix: Update transaction input selectors to use form references 2026-01-08 17:37:56 +05:30
a9e6de83e9
Clean up README by removing duplicate lines
Removed duplicate project name entries.
2026-01-06 21:39:58 +05:30
35da1851af
Merge pull request #3 from void-57/main
feat: Implement multi-chain address recovery from private key and enhance transaction history retrieval with pagination and improved error handling
2026-01-06 21:39:20 +05:30
822f026c65 feat: Implement multi-chain address recovery from private key and enhance transaction history retrieval with pagination and improved error handling 2026-01-06 21:29:29 +05:30
e168e4b9a8 feat : added transaction history ,transaction details and currency selector 2025-05-24 22:05:15 +05:30
17f57a626b feat : added transaction history ,transaction details and currency selector 2025-05-24 22:04:37 +05:30
4c9cf17ef2 feat: add functions to fetch transaction history and details for BSC addresses
- Implemented getTransactionHistory to retrieve a list of transactions for a given address from BscScan API.
- Implemented getTransactionDetails to fetch detailed information about a specific transaction using its hash.
- Added error handling and validation for both functions
2025-05-24 22:01:26 +05:30
6 changed files with 2679 additions and 778 deletions

View File

@ -29,4 +29,4 @@ jobs:
cd ${{ secrets.DEPLOYMENT_LOCATION}}/dappbundle && git clone https://github.com/ranchimall/${{ github.event.repository.name }} cd ${{ secrets.DEPLOYMENT_LOCATION}}/dappbundle && git clone https://github.com/ranchimall/${{ github.event.repository.name }}
cd "${{ secrets.DEPLOYMENT_LOCATION}}/dappbundle/${{ github.event.repository.name }}" && rm -rf .gitattributes .git .github .gitignore cd "${{ secrets.DEPLOYMENT_LOCATION}}/dappbundle/${{ github.event.repository.name }}" && rm -rf .gitattributes .git .github .gitignore
cd ${{ secrets.DEPLOYMENT_LOCATION}}/dappbundle/ && git add . && git commit -m "Workflow updating files of ${{ github.event.repository.name }}" && git push "https://ranchimalldev:${{ secrets.RM_ACCESS_TOKEN }}@github.com/ranchimall/dappbundle.git" cd ${{ secrets.DEPLOYMENT_LOCATION}}/dappbundle/ && git add . && git commit -m "Workflow updating files of ${{ github.event.repository.name }}" && git push "https://saketongit:${{ secrets.RM_ACCESS_TOKEN }}@github.com/ranchimall/dappbundle.git"

View File

@ -1,2 +1,3 @@
# bscwallet # bscwallet
Binance Chain Wallet linked with FLO blockchain address Binance Chain Wallet linked with FLO blockchain address

View File

@ -28,7 +28,7 @@ body {
background-color: rgba(var(--foreground-color), 1); background-color: rgba(var(--foreground-color), 1);
} }
body[data-theme=dark] { body[data-theme="dark"] {
--accent-color: #92a2ff; --accent-color: #92a2ff;
--accent-color-rgb: 160, 182, 255; --accent-color-rgb: 160, 182, 255;
--secondary-color: #d60739; --secondary-color: #d60739;
@ -39,7 +39,7 @@ body[data-theme=dark] {
--green: #00e676; --green: #00e676;
--yellow: rgb(255, 213, 5); --yellow: rgb(255, 213, 5);
} }
body[data-theme=dark] ::-webkit-calendar-picker-indicator { body[data-theme="dark"] ::-webkit-calendar-picker-indicator {
filter: invert(1); filter: invert(1);
} }
@ -63,7 +63,7 @@ strong {
img { img {
-o-object-fit: cover; -o-object-fit: cover;
object-fit: cover; object-fit: cover;
} }
a:where([class]) { a:where([class]) {
@ -90,7 +90,7 @@ a:any-link:focus-visible {
outline: rgba(var(--text-color), 1) 0.1rem solid; outline: rgba(var(--text-color), 1) 0.1rem solid;
} }
input[type=datetime-local] { input[type="datetime-local"] {
width: 100%; width: 100%;
padding: 0.8rem 0.6rem; padding: 0.8rem 0.6rem;
border: none; border: none;
@ -101,7 +101,7 @@ input[type=datetime-local] {
color: inherit; color: inherit;
background-color: rgba(var(--text-color), 0.06); background-color: rgba(var(--text-color), 0.06);
} }
input[type=datetime-local]:focus { input[type="datetime-local"]:focus {
outline: none; outline: none;
box-shadow: 0 0 0 0.1rem var(--accent-color); box-shadow: 0 0 0 0.1rem var(--accent-color);
} }
@ -109,8 +109,8 @@ input[type=datetime-local]:focus {
button, button,
.button { .button {
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
user-select: none; user-select: none;
position: relative; position: relative;
display: inline-flex; display: inline-flex;
border: none; border: none;
@ -224,8 +224,8 @@ a:any-link:focus-visible {
details summary { details summary {
display: flex; display: flex;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
user-select: none; user-select: none;
cursor: pointer; cursor: pointer;
align-items: center; align-items: center;
gap: 1rem; gap: 1rem;
@ -264,8 +264,8 @@ sm-chip {
--padding: 0.5rem 0.8rem; --padding: 0.5rem 0.8rem;
--background: rgba(var(--text-color), 0.06); --background: rgba(var(--text-color), 0.06);
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
user-select: none; user-select: none;
font-weight: 500; font-weight: 500;
} }
sm-chip[selected] { sm-chip[selected] {
@ -604,7 +604,11 @@ ul {
position: absolute; position: absolute;
border-radius: 50%; border-radius: 50%;
transform: scale(0); transform: scale(0);
background: radial-gradient(circle, rgba(var(--text-color), 0.3) 0%, rgba(0, 0, 0, 0) 50%); background: radial-gradient(
circle,
rgba(var(--text-color), 0.3) 0%,
rgba(0, 0, 0, 0) 50%
);
pointer-events: none; pointer-events: none;
} }
@ -699,17 +703,17 @@ ul {
justify-self: flex-start; justify-self: flex-start;
} }
ul[type=circle], ul[type="circle"],
menu[type=circle] { menu[type="circle"] {
padding: 1.5rem 2.5rem; padding: 1.5rem 2.5rem;
list-style: circle; list-style: circle;
} }
ul[type=circle] li, ul[type="circle"] li,
menu[type=circle] li { menu[type="circle"] li {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
ul[type=circle] li:last-of-type, ul[type="circle"] li:last-of-type,
menu[type=circle] li:last-of-type { menu[type="circle"] li:last-of-type {
margin-bottom: 0; margin-bottom: 0;
} }
ul, ul,
@ -773,13 +777,13 @@ menu {
#meta_mask_status_button .icon-wrapper > * { #meta_mask_status_button .icon-wrapper > * {
grid-area: 1/1; grid-area: 1/1;
} }
#meta_mask_status_button[data-status=connected] { #meta_mask_status_button[data-status="connected"] {
pointer-events: none; pointer-events: none;
} }
#meta_mask_status_button[data-status=connected] .icon-wrapper::after { #meta_mask_status_button[data-status="connected"] .icon-wrapper::after {
background-color: var(--green); background-color: var(--green);
} }
#meta_mask_status_button[data-status=disconnected] .icon-wrapper::after { #meta_mask_status_button[data-status="disconnected"] .icon-wrapper::after {
background-color: var(--danger-color); background-color: var(--danger-color);
} }
@ -847,7 +851,8 @@ main {
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
} }
.nav-item__title { .nav-item__title {
transition: opacity 0.2s, transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); transition: opacity 0.2s,
transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
} }
.nav-item--active { .nav-item--active {
color: var(--accent-color); color: var(--accent-color);
@ -870,17 +875,17 @@ main {
overflow: auto; overflow: auto;
grid-area: pages; grid-area: pages;
} }
#page_container[data-page=home] > :nth-child(2) { #page_container[data-page="home"] > :nth-child(2) {
flex: 1; flex: 1;
} }
#page_container[data-page=send] { #page_container[data-page="send"] {
align-items: flex-start; align-items: flex-start;
} }
#page_container[data-page=send] > * { #page_container[data-page="send"] > * {
padding: 1rem; padding: 1rem;
margin: 0 auto; margin: 0 auto;
} }
#page_container[data-page=create] { #page_container[data-page="create"] {
margin: 0 auto; margin: 0 auto;
padding: 4vw 1rem; padding: 4vw 1rem;
gap: 2rem; gap: 2rem;
@ -940,17 +945,30 @@ aside h4 {
gap: 0.5rem; gap: 0.5rem;
} }
#bsc_balance_wrapper { #eth_balance_wrapper {
background-color: rgba(var(--text-color), 0.06); background-color: rgba(var(--text-color), 0.06);
padding: max(1rem, 1.5vw); padding: max(1rem, 1.5vw);
border-radius: 0.5rem; border-radius: 0.5rem;
width: 100%; width: 100%;
} }
#bsc_balance_wrapper li:not(:last-of-type) { #eth_balance_wrapper li:not(:last-of-type) {
border-bottom: solid thin rgba(var(--text-color), 0.3); border-bottom: solid thin rgba(var(--text-color), 0.3);
padding-bottom: 0.5rem; padding-bottom: 0.5rem;
} }
#address_transactions {
width: 100%;
max-width: 32rem;
}
.transaction {
width: 100%;
}
#transactions_list {
width: 100%;
}
#error_section { #error_section {
display: grid; display: grid;
height: 100%; height: 100%;
@ -978,6 +996,7 @@ aside h4 {
position: relative; position: relative;
margin-bottom: 2rem; margin-bottom: 2rem;
} }
.transaction__phase:not(:last-of-type)::after { .transaction__phase:not(:last-of-type)::after {
content: ""; content: "";
position: absolute; position: absolute;
@ -1004,7 +1023,7 @@ aside h4 {
width: 4rem; width: 4rem;
border-radius: 5rem; border-radius: 5rem;
-webkit-animation: popup 1s; -webkit-animation: popup 1s;
animation: popup 1s; animation: popup 1s;
padding: 1rem; padding: 1rem;
} }
.user-action-result__icon.pending { .user-action-result__icon.pending {
@ -1068,17 +1087,24 @@ aside h4 {
padding-bottom: 1rem; padding-bottom: 1rem;
border-bottom: solid thin rgba(var(--text-color), 0.3); border-bottom: solid thin rgba(var(--text-color), 0.3);
} }
.create-buttons {
display: flex;
max-width: 400px;
gap: 1rem;
}
@media only screen and (max-width: 640px) { @media only screen and (max-width: 640px) {
.hide-on-small { .hide-on-small {
display: none; display: none;
} }
#page_container[data-page=home] { #page_container[data-page="home"] {
flex-direction: column; flex-direction: column;
} }
#page_container[data-page=home] > :first-child { #page_container[data-page="home"] > :first-child {
order: 1; order: 1;
} }
.create-buttons {
display: grid;
}
} }
@media only screen and (min-width: 640px) { @media only screen and (min-width: 640px) {
sm-popup { sm-popup {
@ -1166,9 +1192,369 @@ aside h4 {
} }
@media (prefers-reduced-motion) { @media (prefers-reduced-motion) {
::view-transition-group(*), ::view-transition-group(*),
::view-transition-old(*), ::view-transition-old(*),
::view-transition-new(*) { ::view-transition-new(*) {
-webkit-animation: none !important; -webkit-animation: none !important;
animation: none !important; animation: none !important;
} }
} }
.tx-details-container {
max-width: 800px;
margin: 1rem auto;
padding: 1rem;
font-family: inherit;
}
/* Header styling */
.tx-header {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid rgba(var(--text-color), 0.1);
}
.tx-title {
font-size: 1.5rem;
font-weight: 600;
color: rgba(var(--text-color), 0.95);
margin: 0;
}
.tx-card {
background-color: rgba(var(--foreground-color), 1);
border-radius: 0.75rem;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
border: 1px solid rgba(var(--text-color), 0.1);
margin-top: 1rem;
}
.tx-status-header {
display: flex;
align-items: center;
gap: 1rem;
padding: 1.25rem;
background-color: rgba(var(--text-color), 0.03);
border-bottom: 1px solid rgba(var(--text-color), 0.1);
}
.status-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
flex-shrink: 0;
}
.status-indicator.confirmed {
background-color: var(--color-success);
box-shadow: 0 0 0 4px rgba(var(--color-success-rgb), 0.2);
}
.status-indicator.pending {
background-color: var(--color-warning);
box-shadow: 0 0 0 4px rgba(var(--color-warning-rgb), 0.2);
}
.status-details {
flex-grow: 1;
}
.status-title {
font-size: 1.15rem;
font-weight: 600;
color: rgba(var(--text-color), 0.95);
margin: 0;
}
.status-subtext {
font-size: 0.85rem;
color: rgba(var(--text-color), 0.7);
margin: 0.25rem 0 0;
}
.tx-info-grid {
padding: 1.25rem;
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.tx-address-section {
display: flex;
align-items: stretch;
gap: 1rem;
background: rgba(var(--text-color), 0.02);
padding: 1rem;
border-radius: 0.5rem;
}
.address-card {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.address-label {
font-size: 0.75rem;
font-weight: 500;
color: rgba(var(--text-color), 0.6);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.address-value {
font-family: "Roboto Mono", monospace;
font-size: 0.85rem;
color: rgba(var(--text-color), 0.9);
word-break: break-all;
background: rgba(var(--text-color), 0.05);
padding: 0.5rem 0.75rem;
border-radius: 0.25rem;
}
.tx-arrow {
font-size: 1.5rem;
color: rgba(var(--text-color), 0.4);
display: flex;
align-items: center;
padding: 0 0.5rem;
}
.tx-hash-section {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.section-label {
font-size: 0.75rem;
font-weight: 500;
color: rgba(var(--text-color), 0.6);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.hash-value {
background-color: rgba(var(--text-color), 0.05);
padding: 0.75rem;
border-radius: 0.25rem;
font-family: "Roboto Mono", monospace;
font-size: 0.85rem;
color: rgba(var(--text-color), 0.9);
word-break: break-all;
}
.tx-metrics-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
}
.metric-card {
background-color: rgba(var(--text-color), 0.03);
padding: 1rem;
border-radius: 0.5rem;
text-align: center;
border: 1px solid rgba(var(--text-color), 0.08);
transition: background-color 0.2s ease, transform 0.2s ease;
}
.metric-card:hover {
background-color: rgba(var(--text-color), 0.06);
transform: translateY(-2px);
}
.metric-label {
font-size: 0.75rem;
font-weight: 500;
color: rgba(var(--text-color), 0.6);
margin-bottom: 0.5rem;
text-transform: uppercase;
letter-spacing: 0.5px;
display: block;
}
.metric-value {
font-size: 0.95rem;
font-weight: 500;
color: rgba(var(--text-color), 0.95);
word-break: break-word;
}
.tx-actions {
display: flex;
justify-content: space-between;
gap: 1rem;
padding: 1.25rem;
border-top: 1px solid rgba(var(--text-color), 0.1);
background-color: rgba(var(--text-color), 0.03);
}
.tx-actions .button {
flex: 1;
}
@media (max-width: 768px) {
.tx-address-section {
flex-direction: column;
gap: 0.75rem;
align-items: stretch;
}
.tx-arrow {
transform: rotate(90deg);
margin: 0.5rem auto;
padding: 0;
}
.tx-metrics-grid {
grid-template-columns: 1fr 1fr;
}
}
@media (max-width: 576px) {
.tx-header {
padding-bottom: 0.75rem;
}
.tx-status-header {
padding: 1rem;
gap: 0.75rem;
}
.status-title {
font-size: 1.1rem;
}
.tx-info-grid {
padding: 1rem;
gap: 1.25rem;
}
.tx-address-section {
padding: 0.75rem;
}
.tx-metrics-grid {
grid-template-columns: 1fr;
}
.tx-actions {
flex-direction: column;
padding: 1rem;
}
}
/* Valuation toggle styles */
.valuation-toggle {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.85rem;
color: rgba(var(--text-color), 0.8);
margin-top: 0.5rem;
margin-right: 0.5rem;
}
.toggle-switch {
position: relative;
display: inline-block;
width: 3rem;
height: 1.5rem;
}
.toggle-switch input {
opacity: 0;
width: 0;
height: 0;
}
.toggle-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(var(--text-color), 0.2);
transition: 0.4s;
border-radius: 1.5rem;
}
.toggle-slider:before {
position: absolute;
content: "";
height: 1.1rem;
width: 1.1rem;
left: 0.2rem;
bottom: 0.2rem;
background-color: white;
transition: 0.4s;
border-radius: 50%;
}
input:checked + .toggle-slider {
background-color: var(--accent-color);
}
input:checked + .toggle-slider:before {
transform: translateX(1.5rem);
}
.transaction-controls {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
margin-bottom: 1rem;
padding: 0.5rem;
background-color: rgba(var(--text-color), 0.03);
border-radius: 0.5rem;
border: 1px solid rgba(var(--text-color), 0.08);
}
.filter-control {
display: flex;
align-items: center;
gap: 0.5rem;
}
.filter-control label {
font-size: 0.9rem;
color: rgba(var(--text-color), 0.8);
font-weight: 500;
}
.filter-control select {
padding: 0.4rem 0.6rem;
border-radius: 0.4rem;
border: 1px solid rgba(var(--text-color), 0.1);
background-color: rgba(var(--foreground-color), 1);
color: rgba(var(--text-color), 0.9);
font-size: 0.9rem;
cursor: pointer;
outline: none;
}
.margin-left-auto + .margin-left-auto {
display: none !important;
}
.filter-control select:focus {
border-color: var(--accent-color);
}
#bsc_balance_wrapper {
background-color: rgba(var(--text-color), 0.06);
padding: max(1rem, 1.5vw);
border-radius: 0.5rem;
width: 100%;
}
#bsc_balance_wrapper li:not(:last-of-type) {
border-bottom: solid thin rgba(var(--text-color), 0.3);
padding-bottom: 0.5rem;
}

2374
index.html

File diff suppressed because it is too large Load Diff

View File

@ -1,363 +1,435 @@
(function (EXPORTS) {
(function (EXPORTS) { //bscOperator v1.0.2 //bscOperator v1.0.2
/* ETH Crypto and API Operator */ /* ETH Crypto and API Operator */
if (!window.ethers) if (!window.ethers) return console.error("ethers.js not found");
return console.error('ethers.js not found')
const bscOperator = EXPORTS; const bscOperator = EXPORTS;
const isValidAddress = bscOperator.isValidAddress = (address) => { const isValidAddress = (bscOperator.isValidAddress = (address) => {
try { try {
// Check if the address is a valid checksum address // Check if the address is a valid checksum address
const isValidChecksum = ethers.utils.isAddress(address); const isValidChecksum = ethers.utils.isAddress(address);
// Check if the address is a valid non-checksum address // Check if the address is a valid non-checksum address
const isValidNonChecksum = ethers.utils.getAddress(address) === address.toLowerCase(); const isValidNonChecksum =
ethers.utils.getAddress(address) === address.toLowerCase();
return isValidChecksum || isValidNonChecksum; return isValidChecksum || isValidNonChecksum;
} catch (error) { } catch (error) {
return false; return false;
} }
} });
const BEP20ABI = [ const BEP20ABI = [
{ {
"constant": true, constant: true,
"inputs": [], inputs: [],
"name": "name", name: "name",
"outputs": [ outputs: [
{ {
"name": "", name: "",
"type": "string" type: "string",
} },
], ],
"payable": false, payable: false,
"stateMutability": "view", stateMutability: "view",
"type": "function" type: "function",
}, },
{ {
"constant": false, constant: false,
"inputs": [ inputs: [
{ {
"name": "_spender", name: "_spender",
"type": "address" type: "address",
}, },
{ {
"name": "_value", name: "_value",
"type": "uint256" type: "uint256",
} },
], ],
"name": "approve", name: "approve",
"outputs": [ outputs: [
{ {
"name": "", name: "",
"type": "bool" type: "bool",
} },
], ],
"payable": false, payable: false,
"stateMutability": "nonpayable", stateMutability: "nonpayable",
"type": "function" type: "function",
}, },
{ {
"constant": true, constant: true,
"inputs": [], inputs: [],
"name": "totalSupply", name: "totalSupply",
"outputs": [ outputs: [
{ {
"name": "", name: "",
"type": "uint256" type: "uint256",
} },
], ],
"payable": false, payable: false,
"stateMutability": "view", stateMutability: "view",
"type": "function" type: "function",
}, },
{ {
"constant": false, constant: false,
"inputs": [ inputs: [
{ {
"name": "_from", name: "_from",
"type": "address" type: "address",
}, },
{ {
"name": "_to", name: "_to",
"type": "address" type: "address",
}, },
{ {
"name": "_value", name: "_value",
"type": "uint256" type: "uint256",
} },
], ],
"name": "transferFrom", name: "transferFrom",
"outputs": [ outputs: [
{ {
"name": "", name: "",
"type": "bool" type: "bool",
} },
], ],
"payable": false, payable: false,
"stateMutability": "nonpayable", stateMutability: "nonpayable",
"type": "function" type: "function",
}, },
{ {
"constant": true, constant: true,
"inputs": [], inputs: [],
"name": "decimals", name: "decimals",
"outputs": [ outputs: [
{ {
"name": "", name: "",
"type": "uint8" type: "uint8",
} },
], ],
"payable": false, payable: false,
"stateMutability": "view", stateMutability: "view",
"type": "function" type: "function",
}, },
{ {
"constant": true, constant: true,
"inputs": [ inputs: [
{ {
"name": "_owner", name: "_owner",
"type": "address" type: "address",
} },
], ],
"name": "balanceOf", name: "balanceOf",
"outputs": [ outputs: [
{ {
"name": "balance", name: "balance",
"type": "uint256" type: "uint256",
} },
], ],
"payable": false, payable: false,
"stateMutability": "view", stateMutability: "view",
"type": "function" type: "function",
}, },
{ {
"constant": true, constant: true,
"inputs": [], inputs: [],
"name": "symbol", name: "symbol",
"outputs": [ outputs: [
{ {
"name": "", name: "",
"type": "string" type: "string",
} },
], ],
"payable": false, payable: false,
"stateMutability": "view", stateMutability: "view",
"type": "function" type: "function",
}, },
{ {
"constant": false, constant: false,
"inputs": [ inputs: [
{ {
"name": "_to", name: "_to",
"type": "address" type: "address",
}, },
{ {
"name": "_value", name: "_value",
"type": "uint256" type: "uint256",
} },
], ],
"name": "transfer", name: "transfer",
"outputs": [ outputs: [
{ {
"name": "", name: "",
"type": "bool" type: "bool",
} },
], ],
"payable": false, payable: false,
"stateMutability": "nonpayable", stateMutability: "nonpayable",
"type": "function" type: "function",
}, },
{ {
"constant": true, constant: true,
"inputs": [ inputs: [
{ {
"name": "_owner", name: "_owner",
"type": "address" type: "address",
}, },
{ {
"name": "_spender", name: "_spender",
"type": "address" type: "address",
} },
], ],
"name": "allowance", name: "allowance",
"outputs": [ outputs: [
{ {
"name": "", name: "",
"type": "uint256" type: "uint256",
} },
], ],
"payable": false, payable: false,
"stateMutability": "view", stateMutability: "view",
"type": "function" type: "function",
}, },
{ {
"payable": true, payable: true,
"stateMutability": "payable", stateMutability: "payable",
"type": "fallback" type: "fallback",
}, },
{ {
"anonymous": false, anonymous: false,
"inputs": [ inputs: [
{ {
"indexed": true, indexed: true,
"name": "owner", name: "owner",
"type": "address" type: "address",
}, },
{ {
"indexed": true, indexed: true,
"name": "spender", name: "spender",
"type": "address" type: "address",
}, },
{ {
"indexed": false, indexed: false,
"name": "value", name: "value",
"type": "uint256" type: "uint256",
} },
], ],
"name": "Approval", name: "Approval",
"type": "event" type: "event",
}, },
{ {
"anonymous": false, anonymous: false,
"inputs": [ inputs: [
{ {
"indexed": true, indexed: true,
"name": "from", name: "from",
"type": "address" type: "address",
}, },
{ {
"indexed": true, indexed: true,
"name": "to", name: "to",
"type": "address" type: "address",
}, },
{ {
"indexed": false, indexed: false,
"name": "value", name: "value",
"type": "uint256" type: "uint256",
} },
], ],
"name": "Transfer", name: "Transfer",
"type": "event" type: "event",
} },
] ];
const CONTRACT_ADDRESSES = { const CONTRACT_ADDRESSES = {
usdc: "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", usdc: "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d",
usdt: "0x55d398326f99059ff775485246999027b3197955" usdt: "0x55d398326f99059ff775485246999027b3197955",
} };
function getProvider() { function getProvider() {
// switches provider based on whether the user is using MetaMask or not // switches provider based on whether the user is using MetaMask or not
const bscMainnet = { const bscMainnet = {
chainId: 56, chainId: 56,
name: 'binance', name: "binance",
rpc: 'https://bsc-dataseed.binance.org/', rpc: "https://bsc-dataseed.binance.org/",
explorer: 'https://bscscan.com' explorer: "https://bscscan.com",
}; };
if (window.ethereum) { if (window.ethereum) {
return new ethers.providers.Web3Provider(window.ethereum); return new ethers.providers.Web3Provider(window.ethereum);
} else { } else {
return new ethers.providers.JsonRpcProvider(bscMainnet.rpc, bscMainnet) return new ethers.providers.JsonRpcProvider(bscMainnet.rpc, bscMainnet);
} }
} }
function connectToMetaMask() { function connectToMetaMask() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// if (typeof window.ethereum === "undefined") // if (typeof window.ethereum === "undefined")
// return reject("MetaMask not installed"); // return reject("MetaMask not installed");
return resolve(true) return resolve(true);
ethereum ethereum
.request({ method: 'eth_requestAccounts' }) .request({ method: "eth_requestAccounts" })
.then((accounts) => { .then((accounts) => {
console.log('Connected to MetaMask') console.log("Connected to MetaMask");
return resolve(accounts) return resolve(accounts);
}) })
.catch((err) => { .catch((err) => {
console.log(err) console.log(err);
return reject(err) return reject(err);
}) });
}) });
} }
const getTransactionHistory = (bscOperator.getTransactionHistory = async (
address,
const getBalance = bscOperator.getBalance = async (address) => { cursor = null
) => {
try { try {
if (!address || !isValidAddress(address)) if (!address || !isValidAddress(address))
return new Error('Invalid address'); return new Error("Invalid address");
// Get the balance
// Moralis API endpoint for BSC transactions
const MORALIS_API_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJub25jZSI6IjQyZWNiMjk0LTBiMGItNDg4Yy1hNjUwLTE4NmJhMjFjNjNhYyIsIm9yZ0lkIjoiNDg4NzAzIiwidXNlcklkIjoiNTAyODExIiwidHlwZUlkIjoiZjE5ZmZjYTYtNDllMS00NTdlLTllNjgtMGI1MDIyODU2N2Q4IiwidHlwZSI6IlBST0pFQ1QiLCJpYXQiOjE3Njc1NDkxNDQsImV4cCI6NDkyMzMwOTE0NH0.yr_jtBCrrid4Y5d48iTwJ4PwgMOZn8mwWyiQ7dAmNvw";
// Fetch 10 transactions per page
const url = `https://deep-index.moralis.io/api/v2/${address}?chain=bsc&limit=10${cursor ? `&cursor=${cursor}` : ''}`;
const response = await fetch(url, {
headers: {
"Accept": "application/json",
"X-API-Key": MORALIS_API_KEY
}
});
const data = await response.json();
if (data.result && Array.isArray(data.result)) {
// Get current block number to calculate confirmations
const provider = getProvider();
const currentBlockNumber = await provider.getBlockNumber();
const transactions = data.result.map((tx) => ({
hash: tx.hash,
from: tx.from_address,
to: tx.to_address,
value: tx.value,
timeStamp: Math.floor(new Date(tx.block_timestamp).getTime() / 1000),
blockNumber: tx.block_number,
confirmations: currentBlockNumber - parseInt(tx.block_number),
gasPrice: tx.gas_price,
gasUsed: tx.receipt_gas_used,
}));
// Return transactions along with cursor for next page
return {
transactions: transactions,
nextCursor: data.cursor || null,
hasMore: !!data.cursor
};
} else {
console.error("Error fetching transaction history:", data.message || "No results");
return {
transactions: [],
nextCursor: null,
hasMore: false
};
}
} catch (error) {
console.error("Error:", error.message);
return error;
}
});
const getTransactionDetails = (bscOperator.getTransactionDetails = async (
txHash
) => {
try {
if (!txHash || !/^0x([A-Fa-f0-9]{64})$/.test(txHash)) return null;
const provider = getProvider();
const tx = await provider.getTransaction(txHash);
if (!tx) return null;
const receipt = await provider.getTransactionReceipt(txHash);
let timestamp = null;
let confirmations = 0;
if (tx.blockNumber) {
const block = await provider.getBlock(tx.blockNumber);
timestamp = block.timestamp;
const currentBlockNumber = await provider.getBlockNumber();
confirmations = currentBlockNumber - tx.blockNumber;
}
return {
hash: tx.hash,
from: tx.from,
to: tx.to,
value: tx.value,
gasPrice: tx.gasPrice,
gasUsed: receipt ? receipt.gasUsed : null,
blockNumber: tx.blockNumber,
timeStamp: timestamp,
confirmations: confirmations,
status: receipt ? (receipt.status ? "success" : "failed") : "pending",
};
} catch (error) {
console.error("Error fetching transaction details:", error);
return null;
}
});
const getBalance = (bscOperator.getBalance = async (address) => {
try {
if (!address || !isValidAddress(address)) {
return new Error("Invalid address");
}
const provider = getProvider(); const provider = getProvider();
const balanceWei = await provider.getBalance(address); const balanceWei = await provider.getBalance(address);
const balanceEth = parseFloat(ethers.utils.formatEther(balanceWei)); const balanceEth = parseFloat(ethers.utils.formatEther(balanceWei));
return balanceEth; return balanceEth;
} catch (error) { } catch (error) {
console.error('Error:', error.message); console.error("Error in getBalance:", error);
return error; return error;
} }
} });
const getTokenBalance = (bscOperator.getTokenBalance = async (
address,
token,
{ contractAddress } = {}
) => {
const getTokenBalance = bscOperator.getTokenBalance = async (address, token, { contractAddress } = {}) => {
try { try {
if (!address) { if (!address) {
throw new Error("Address not specified"); throw new Error("Address not specified");
} }
if (!token) { if (!token) {
throw new Error("Token not specified"); throw new Error("Token not specified");
} }
if (!CONTRACT_ADDRESSES[token] && !contractAddress) { if (!CONTRACT_ADDRESSES[token] && !contractAddress) {
throw new Error("Contract address of token not available"); throw new Error("Contract address of token not available");
} }
const provider = getProvider(); // Ensure this returns a valid provider for BSC const provider = getProvider();
const contract = new ethers.Contract(CONTRACT_ADDRESSES[token] || contractAddress, BEP20ABI, provider); const contract = new ethers.Contract(
CONTRACT_ADDRESSES[token] || contractAddress,
BEP20ABI,
provider
);
let balance = await contract.balanceOf(address); let balance = await contract.balanceOf(address);
// Assuming 18 decimals for most tokens like USDT and USDC*****************************************************
// const decimals = 0.00;
const decimals = 18; const decimals = 18;
const formattedDecimals = decimals.toFixed(1); // This will convert 18 to "18.00" balance = parseFloat(ethers.utils.formatUnits(balance, decimals));
console.log(formattedDecimals); // Outputs: "18.0"
balance = parseFloat(ethers.utils.formatUnits(balance, decimals));
// Format the balance to 2 decimal places for display
balance = balance.toFixed(2);
return balance; return balance;
} } catch (e) {
catch (e) { console.error("Error in getTokenBalance:", e);
// console.error("Error getting token balance:", e.message); throw e;
// throw new Error("Failed to get token balance");
} }
} });
// Example usage: const estimateGas = (bscOperator.estimateGas = async ({
// Ensure MetaMask is connected and BSC network is selected in MetaMask privateKey,
const address = '0xYourAddressHere'; // Replace with your actual address receiver,
(async () => { amount,
try { }) => {
const usdtBalance = await getTokenBalance(address, 'USDT');
const bnbBalance = await getTokenBalance(address, 'BNB');
console.log('USDT Balance:', usdtBalance);
console.log('BNB Balance:', bnbBalance);
} catch (error) {
console.error('Error fetching balances:', error.message);
}
})();
const estimateGas = bscOperator.estimateGas = async ({ privateKey, receiver, amount }) => {
try { try {
const provider = getProvider(); const provider = getProvider();
const signer = new ethers.Wallet(privateKey, provider); const signer = new ethers.Wallet(privateKey, provider);
@ -367,61 +439,79 @@
value: ethers.utils.parseUnits(amount, "ether"), value: ethers.utils.parseUnits(amount, "ether"),
}); });
} catch (e) { } catch (e) {
throw new Error(e) throw new Error(e);
} }
} });
const sendTransaction = bscOperator.sendTransaction = async ({ privateKey, receiver, amount }) => { const sendTransaction = (bscOperator.sendTransaction = async ({
privateKey,
receiver,
amount,
}) => {
try { try {
const provider = getProvider(); const provider = getProvider();
const signer = new ethers.Wallet(privateKey, provider); const signer = new ethers.Wallet(privateKey, provider);
const limit = await estimateGas({ privateKey, receiver, amount })
// Creating and sending the transaction object const limit = await estimateGas({ privateKey, receiver, amount });
return signer.sendTransaction({
const tx = await signer.sendTransaction({
to: receiver, to: receiver,
value: ethers.utils.parseUnits(amount, "ether"), value: ethers.utils.parseUnits(amount, "ether"),
gasLimit: limit, gasLimit: limit,
nonce: signer.getTransactionCount(), nonce: await signer.getTransactionCount(),
maxPriorityFeePerGas: ethers.utils.parseUnits("2", "gwei"), maxPriorityFeePerGas: ethers.utils.parseUnits("2", "gwei"),
}) });
return tx;
} catch (e) { } catch (e) {
throw new Error(e) console.error("Error in sendTransaction:", e);
throw e;
} }
}; });
const sendToken = bscOperator.sendToken = async ({ token, privateKey, amount, receiver, contractAddress }) => { const sendToken = (bscOperator.sendToken = async ({
// Create a wallet using the private key token,
const wallet = new ethers.Wallet(privateKey, getProvider()); privateKey,
amount,
receiver,
contractAddress,
}) => {
try {
const wallet = new ethers.Wallet(privateKey, getProvider());
// Contract interface const tokenContract = new ethers.Contract(
const tokenContract = new ethers.Contract(CONTRACT_ADDRESSES[token] || contractAddress, BEP20ABI, wallet); CONTRACT_ADDRESSES[token] || contractAddress,
BEP20ABI,
wallet
);
// Fetch the correct number of decimals for the token const decimals = await tokenContract.decimals();
const decimals = await tokenContract.decimals();
// Convert the amount to the smallest unit of the token const amountWei = ethers.utils.parseUnits(amount.toString(), decimals);
const amountWei = ethers.utils.parseUnits(amount.toString(), decimals);
// Estimate gas limit for the transaction const gasLimit = await tokenContract.estimateGas.transfer(
const gasLimit = await tokenContract.estimateGas.transfer(receiver, amountWei); receiver,
amountWei
);
// Get the current gas price const gasPrice = await wallet.provider.getGasPrice();
const gasPrice = await wallet.provider.getGasPrice();
// Calculate the gas cost const gasCost = gasPrice.mul(gasLimit);
const gasCost = gasPrice.mul(gasLimit);
console.log(`Gas cost: ${ethers.utils.formatEther(gasCost)} BNB`); const balance = await wallet.getBalance();
// Check if wallet has enough balance to cover gas fees if (balance.lt(gasCost)) {
const balance = await wallet.getBalance(); throw new Error("Insufficient funds for gas fee");
if (balance.lt(gasCost)) { }
throw new Error("Insufficient funds for gas fee");
const tx = await tokenContract.transfer(receiver, amountWei, {
gasLimit,
gasPrice,
});
return tx;
} catch (e) {
console.error("Error in sendToken:", e);
throw e;
} }
});
})("object" === typeof module ? module.exports : (window.bscOperator = {}));
// Call the transfer function on the USDC contract
return tokenContract.transfer(receiver, amountWei, { gasLimit, gasPrice });
}
})('object' === typeof module ? module.exports : window.bscOperator = {});

File diff suppressed because one or more lines are too long