Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:dynamic wallet selection #27

Merged
merged 25 commits into from
Jan 31, 2025
Merged
Changes from 23 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ece3293
feat: add external wallet balance option
Pratham-19 Nov 24, 2024
2e1b9e7
feat: revet changes
Pratham-19 Nov 24, 2024
ef6988d
feat: add check token balance
Pratham-19 Nov 24, 2024
c4fa69b
feat:dynamic wallet selection
SarveshLimaye Nov 28, 2024
e5998db
fix:fail tx if not valid wallet name
SarveshLimaye Nov 30, 2024
6b94d22
feat: add wallet backup
chandrabosep Dec 3, 2024
48e50a4
feat: remove token option
Pratham-19 Dec 6, 2024
0703fa4
Merge branch 'rsksmart:main' into main
Pratham-19 Dec 6, 2024
44e5d8b
feat: resolve merge conflicts
Pratham-19 Dec 6, 2024
73d21a6
chore: u[date error comment
Pratham-19 Dec 6, 2024
7cc11a5
fix: wallet address fetch
Pratham-19 Dec 6, 2024
7ba62af
fix: add erc20 contract check
Pratham-19 Dec 6, 2024
42b69cb
feat:show transaction history for current wallet
SarveshLimaye Dec 6, 2024
920bd62
refactor: streamline wallet data handling and improve backup process
chandrabosep Dec 7, 2024
25e8cdd
chore: update token address
Pratham-19 Dec 10, 2024
7749ce2
chore: rmv debug console
Pratham-19 Dec 10, 2024
ff2e1fd
chore:history command enhancements
SarveshLimaye Dec 16, 2024
5b85028
chore: remove blank space
Pratham-19 Dec 17, 2024
9627a62
chore: change token address
Pratham-19 Dec 17, 2024
83a7c43
chore: rmv console import
Pratham-19 Dec 17, 2024
d97a9b9
feat: add viem erc20Abi
Pratham-19 Dec 17, 2024
ce53f72
chore:history command enhancements
SarveshLimaye Dec 18, 2024
7a7bdcf
Merge branch 'feat-backup' into pr-merge
chrisarevalodev Jan 9, 2025
895f596
merge with PR 41
chrisarevalodev Jan 9, 2025
a32c2d4
chore:conflicts resolved
SarveshLimaye Jan 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -370,6 +370,52 @@ Output example:
🔗 View on Explorer: https://explorer.testnet.rootstock.io/address/0x0000000000000000000000000000000001000006
```

### 9. Fetch Wallet History

The history command allows you to fetch the transaction history for a wallet on the Rootstock blockchain. This includes transactions such as ERC20, ERC721, and external transfers. You can specify whether to fetch the history from the Mainnet or Testnet by providing the appropriate flag

#### Mainnet

With arguments:

```bash
rsk-cli history --apiKey <apiKey> --number <number>
```

Without arguments:

```bash
rsk-cli history
```

#### Testnet

With arguments:

```bash
rsk-cli history --testnet --apiKey <apiKey> --number <number>
```

Without arguments

```bash
rsk-cli history --testnet
```

Output example:

```
? 🔒 Enter Alchemy API key to fetch history: ********************************
🔍 Fetching transaction history on Rootstack Testnet for 0x19661D036D4e590948b9c00eef3807b88fBfA8e1 ...
✅ Transfer:
From: 0x19661d036d4e590948b9c00eef3807b88fbfa8e1
To: 0xb45805aead9407f5c7860ff8eccaedd4d0ab36a6
Token: ETH
Value: 0.000003
Tx Hash: 0xde678614cd9e20fe5891c25069afef680174456b104f31c9078eb486abd95a64

```

## Contributing

We welcome contributions from the community. Please fork the repository and submit pull requests with your changes. Ensure your code adheres to the project's main objective.
20 changes: 18 additions & 2 deletions bin/index.ts
Original file line number Diff line number Diff line change
@@ -9,20 +9,25 @@ import chalk from "chalk";
import { deployCommand } from "../src/commands/deploy.js";
import { verifyCommand } from "../src/commands/verify.js";
import { ReadContract } from "../src/commands/contract.js";
import { Address } from "viem";
import { bridgeCommand } from "../src/commands/bridge.js";
import { historyCommand } from "../src/commands/history.js";

interface CommandOptions {
testnet?: boolean;
address?: string;
address?: Address;
contract?: Address;
value?: string;
txid?: string;
abi?: string;
bytecode?: string;
apiKey?: string;
args?: any;
json?: any;
name?: string;
decodedArgs?: any;
wallet?: string;
number?: string;
}

const orange = chalk.rgb(255, 165, 0);
@@ -58,8 +63,9 @@ program
.description("Check the balance of the saved wallet")
.option("-t, --testnet", "Check the balance on the testnet")
.option("--wallet <wallet>", "Name of the wallet")
.option("-a ,--address <address>", "Token holder address")
.action(async (options: CommandOptions) => {
await balanceCommand(!!options.testnet, options.wallet!);
await balanceCommand(!!options.testnet, options.wallet!, options.address);
});

program
@@ -158,4 +164,14 @@ program
await bridgeCommand(!!options.testnet, options.wallet!);
});

program
.command("history")
.description("Fetch history for current wallet")
.option("--apiKey <apiKey", "Alchemy API key")
.option("--number <number>", "Number of transactions to fetch")
.option("-t, --testnet", "History of wallet on the testnet")
.action(async (options: CommandOptions) => {
await historyCommand(!!options.testnet, options.apiKey!, options.number!);
});

program.parse(process.argv);
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -9,10 +9,12 @@
},
"scripts": {
"build": "tsc",
"dev": "tsc -w",
"wallet": "pnpm run build && node dist/bin/index.js wallet",
"balance": "pnpm run build && node dist/bin/index.js balance",
"transfer": "pnpm run build && node dist/bin/index.js transfer --testnet --address 0xa5f45f5bddefC810C48aCC1D5CdA5e5a4c6BC59E --value 0.001",
"tx-status": "pnpm run build && node dist/bin/index.js tx --testnet --txid 0x876a0a9b167889350c41930a4204e5d9acf5704a7f201447a337094189af961c4"
"tx-status": "pnpm run build && node dist/bin/index.js tx --testnet --txid 0x876a0a9b167889350c41930a4204e5d9acf5704a7f201447a337094189af961c4",
"history": "pnpm run build && node dist/bin/index.js history"
},
"keywords": [
"rootstock",
139 changes: 118 additions & 21 deletions src/commands/balance.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
import ViemProvider from "../utils/viemProvider.js";
import fs from "fs";
import chalk from "chalk";
import inquirer from "inquirer";
import {
getTokenInfo,
isERC20Contract,
resolveTokenAddress,
} from "../utils/tokenHelper.js";
import ora from "ora";
import {
getAddress,
isValidContract,
validateAndFormatAddress,
} from "../utils/index.js";
import { Address, formatUnits } from "viem";
import { TOKENS } from "../constants/tokenAdress.js";
import fs from "fs";
import { walletFilePath } from "../utils/constants.js";

export async function balanceCommand(testnet: boolean, name: string) {
try {
if (!fs.existsSync(walletFilePath)) {
console.log(
chalk.red("🚫 No saved wallet found. Please create a wallet first.")
);
return;
}
export async function balanceCommand(
testnet: boolean,
walletName: string,
holderAddress?: Address
) {
const spinner = ora();

try {
const walletsData = JSON.parse(fs.readFileSync(walletFilePath, "utf8"));

if (!walletsData.currentWallet || !walletsData.wallets) {
@@ -26,15 +39,15 @@ export async function balanceCommand(testnet: boolean, name: string) {
const { currentWallet, wallets } = walletsData;
let wallet = wallets[currentWallet];

if (name) {
if (!wallets[name]) {
if (walletName) {
if (!wallets[walletName]) {
console.log(
chalk.red("⚠️ Wallet with the provided name does not exist.")
);

throw new Error();
return;
} else {
wallet = wallets[name];
wallet = wallets[walletName];
}
}

@@ -45,22 +58,104 @@ export async function balanceCommand(testnet: boolean, name: string) {
return;
}

const targetAddress = getAddress(address);

if (!targetAddress) {
return;
}

const provider = new ViemProvider(testnet);
const client = await provider.getPublicClient();

const balance = await client.getBalance({ address });
const { token } = await inquirer.prompt({
type: "list",
name: "token",
message: "Select token to check balance:",
choices: ["rBTC", ...Object.keys(TOKENS), "Custom Token"],
});

const rbtcBalance = Number(balance) / 10 ** 18;
if (token === "rBTC") {
spinner.start(chalk.white("🔍 Checking balance..."));
const balance = await client.getBalance({ address: targetAddress });
const rbtcBalance = formatUnits(balance, 18);

console.log(chalk.white(`📄 Wallet Address:`), chalk.green(address));
console.log(
chalk.white(`🌐 Network:`),
chalk.green(testnet ? "Rootstock Testnet" : "Rootstock Mainnet")
spinner.succeed(chalk.green("Balance retrieved successfully"));

console.log(
chalk.white(`📄 Wallet Address:`),
chalk.green(targetAddress)
);
console.log(
chalk.white(`🌐 Network:`),
chalk.green(testnet ? "Rootstock Testnet" : "Rootstock Mainnet")
);
console.log(
chalk.white(`💰 Current Balance:`),
chalk.green(`${rbtcBalance} RBTC`)
);
console.log(
chalk.blue(
`🔗 Ensure that transactions are being conducted on the correct network.`
)
);
return;
}

let tokenAddress: Address;

if (token === "Custom Token") {
spinner.stop();
const { address } = await inquirer.prompt({
type: "input",
name: "address",
message: "Enter the token address:",
validate: async (input: string) => {
try {
const address = input as Address;
const formattedContractAddress = validateAndFormatAddress(address);
if (!formattedContractAddress) {
console.log(chalk.red());
return "🚫 Invalid contract address";
}
if (!(await isValidContract(client, formattedContractAddress))) {
return "🚫 Invalid contract address or contract not found";
}
if (!(await isERC20Contract(client, formattedContractAddress))) {
return "🚫 Invalid contract address, only ERC20 tokens are supported";
}
return true;
} catch {
return false;
}
},
});
tokenAddress = address.toLowerCase() as Address;
} else {
tokenAddress = resolveTokenAddress(token, testnet);
}

spinner.start(chalk.white("🔍 Checking balance..."));

const { balance, decimals, name, symbol } = await getTokenInfo(
client,
tokenAddress,
targetAddress
);
const formattedBalance = formatUnits(balance, decimals);

spinner.succeed(chalk.green("Balance retrieved successfully"));

console.log(
chalk.white(`💰 Current Balance:`),
chalk.green(`${rbtcBalance} RBTC`)
chalk.white(`📄 Token Information:
Name: ${chalk.green(name)}
Contract: ${chalk.green(tokenAddress)}
👤 Holder Address: ${chalk.green(targetAddress)}
💰 Balance: ${chalk.green(`${formattedBalance} ${symbol}`)}
🌐 Network: ${chalk.green(
testnet ? "Rootstock Testnet" : "Rootstock Mainnet"
)}`)
);

console.log(
chalk.blue(
`🔗 Ensure that transactions are being conducted on the correct network.`
@@ -75,5 +170,7 @@ export async function balanceCommand(testnet: boolean, name: string) {
} else {
console.error(chalk.red("🚨 An unknown error occurred."));
}
} finally {
spinner.stop();
}
}
Loading