Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
1b32861
feat: add RNS resolve command
97woo Jul 21, 2025
ed4aff6
Merge upstream/main and resolve conflicts
97woo Jul 22, 2025
c64d1d8
docs: add RNS resolve command documentation to README
97woo Jul 22, 2025
3ac897a
feat: add RNS helper module for domain resolution
97woo Aug 11, 2025
5721792
feat: add RNS support to transfer command
97woo Aug 11, 2025
d509f44
feat: add RNS support to batch-transfer command
97woo Aug 11, 2025
75261b3
docs: update README with RNS integration examples
97woo Aug 11, 2025
1be9f1e
docs: use verified RNS domains in examples
97woo Aug 11, 2025
e5b0ad4
fix: resolve merge conflicts with upstream/main
97woo Aug 11, 2025
1925b56
refactor: update RNS implementation based on PR review
97woo Aug 27, 2025
6194850
style: apply wallet.ts pattern with helper functions
97woo Aug 27, 2025
002e058
refactor: apply object parameter pattern to RNS functions
97woo Aug 27, 2025
dfdb7e2
fix: resolve RNS module import issues and remove code comments
97woo Sep 7, 2025
987a1ec
fix: improve code quality and type safety
97woo Sep 7, 2025
eb69e44
fix: address PR review comments for RNS integration
97woo Sep 11, 2025
f05b834
Merge remote-tracking branch 'upstream/main' into feat/add-rns-resolv…
97woo Sep 11, 2025
7c79ead
fix: final cleanup - fix indentation and remove comment
97woo Sep 11, 2025
1018969
fix: improve RNS domain validation with proper length check
97woo Sep 11, 2025
aa44fc8
feat(utils): add Rootstock EIP-1191/EIP-55 address helpers
97woo Sep 28, 2025
db1e42d
fix(rns/resolve/cli): apply chain-aware validation and normalization
97woo Sep 28, 2025
58d757c
fix(balance): use provided address first; fallback to rBTC if prompt …
97woo Sep 28, 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
121 changes: 114 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,19 @@ This command will guide you through the process of wallet management, offering o

### 2. Check Balance

The `balance` command allows you to check the balance of any token on the Rootstock blockchain for any of the saved wallets. You can check the balance on either the mainnet or testnet using the appropriate flags.
The `balance` command allows you to check the balance of any token on the Rootstock blockchain for any of the saved wallets. You can check the balance on either the mainnet or testnet using the appropriate flags. The command now supports RNS domain resolution for checking balances of any address.

#### Mainnet

```bash
# Check balance of your wallet
rsk-cli balance

# Check balance of a specific address
rsk-cli balance --address 0x123...

# Check balance using RNS domain (example with real mainnet domain)
rsk-cli balance --rns testing.rsk
```

Output example:
Expand All @@ -161,7 +168,11 @@ Output example:
Use the `-t` or `--testnet` flag to check the balance on the Rootstock testnet.

```bash
# Check balance on testnet
rsk-cli balance -t

# Check balance using RNS domain on testnet
rsk-cli balance -t --rns testing.rsk
```

Output example:
Expand All @@ -188,7 +199,7 @@ rsk-cli balance --wallet <name>

### 3. Transfer (RBTC and ERC20)

The `transfer` command allows you to transfer both RBTC and ERC20 tokens from your saved wallet to a specified address on the Rootstock blockchain. You can execute transfers on either mainnet or testnet using the appropriate flags.
The `transfer` command allows you to transfer both RBTC and ERC20 tokens from your saved wallet to a specified address on the Rootstock blockchain. You can execute transfers on either mainnet or testnet using the appropriate flags. The command now supports RNS domain resolution for recipient addresses.

#### Interactive Mode

Expand All @@ -205,9 +216,12 @@ rsk-cli transfer -i
#### For RBTC Transfer

```bash
# Basic transfer on mainnet
# Basic transfer on mainnet using address
rsk-cli transfer --address 0xRecipientAddress --value 0.001

# Transfer using RNS domain
rsk-cli transfer --rns testing.rsk --value 0.001

# Transfer on testnet
rsk-cli transfer --testnet --address 0x08C4E4BdAb2473E454B8B2a4400358792786d341 --value 0.001

Expand Down Expand Up @@ -237,12 +251,18 @@ Output example for RBTC transfer:
Add the `--token` flag with the token contract address to transfer ERC20 tokens:

```bash
# Basic token transfer on mainnet
# Basic token transfer on mainnet using address
rsk-cli transfer --token 0xTokenAddress --address 0xRecipientAddress --value 0.1

# Token transfer using RNS domain
rsk-cli transfer --token 0xTokenAddress --rns testing.rsk --value 0.1

# Token transfer on testnet
rsk-cli transfer --testnet --token 0x32Cd6c5831531F96f57d1faf4DDdf0222c4Af8AB --address 0x8A0d290b2EE35eFde47810CA8fF057e109e4190B --value 0.1

# Token transfer on testnet using RNS domain
rsk-cli transfer --testnet --token 0x32Cd6c5831531F96f57d1faf4DDdf0222c4Af8AB --rns testing.rsk --value 0.1

# Using specific wallet
rsk-cli transfer --wallet <n> --testnet --token 0x32Cd6c5831531F96f57d1faf4DDdf0222c4Af8AB --address 0x8A0d290b2EE35eFde47810CA8fF057e109e4190B --value 0.1

Expand Down Expand Up @@ -501,9 +521,9 @@ Output example:
Time: Tue Nov 12 2024 11:46:32 GMT+0700 (Indochina Time)
```

### 9. Fetch Wallet History
### 10. Batch Transfer

The batch-transfer command allows you to send multiple transactions in one batch. This feature supports both interactive mode (manual input) and file-based batch processing, enabling you to transfer rBTC to multiple addresses in a single operation.
The batch-transfer command allows you to send multiple transactions in one batch. This feature supports both interactive mode (manual input) and file-based batch processing, enabling you to transfer rBTC to multiple addresses in a single operation. The command now supports RNS domain resolution for recipient addresses.

#### Interactive Mode

Expand All @@ -512,13 +532,21 @@ In this mode, the CLI will prompt you to enter the recipient addresses and amoun
#### Mainnet

```bash
# Interactive mode without RNS
rsk-cli batch-transfer --interactive

# Interactive mode with RNS support
rsk-cli batch-transfer --interactive --rns
```

#### Testnet

```bash
# Interactive mode without RNS
rsk-cli batch-transfer --testnet --interactive

# Interactive mode with RNS support
rsk-cli batch-transfer --testnet --interactive --rns
```

Output example:
Expand All @@ -545,7 +573,7 @@ Add another transaction? (y/n): n

#### File-based

In this mode, you provide a JSON file containing the batch transactions. The file must include a list of transactions, each specifying the recipient address (address) and the amount (amount). The file should look something like this:
In this mode, you provide a JSON file containing the batch transactions. The file must include a list of transactions, each specifying the recipient address (address) and the amount (amount). With RNS support, you can also use domain names as recipients. The file should look something like this:

```json
[
Expand All @@ -554,16 +582,34 @@ In this mode, you provide a JSON file containing the batch transactions. The fil
]
```

Or with RNS domains (when using --rns flag):

```json
[
{ "to": "testing.rsk", "value": 0.000001 },
{ "to": "rifos.rsk", "value": 0.000001 },
{ "to": "0xDdC94BFde7C64117F35803AeA4FA4F98A7b4f57C", "value": 0.000001 }
]
```

#### Mainnet

```bash
# File-based batch transfer
rsk-cli batch-transfer --file <path/to/file.json>

# File-based batch transfer with RNS resolution
rsk-cli batch-transfer --file <path/to/file.json> --rns
```

#### Testnet

```bash
# File-based batch transfer
rsk-cli batch-transfer --testnet --file <path/to/file.json>

# File-based batch transfer with RNS resolution
rsk-cli batch-transfer --testnet --file <path/to/file.json> --rns
```

Output example:
Expand All @@ -582,6 +628,67 @@ Output example:
⛽ Gas Used: 21000
```

### 11. RNS Resolve

The `resolve` command allows you to interact with the RIF Name Service (RNS) on the Rootstock blockchain. You can perform both forward resolution (domain to address) and reverse resolution (address to domain name).

#### Forward Resolution (Domain to Address)

Convert an RNS domain name to its associated address:

##### Mainnet

```bash
rsk-cli resolve testing.rsk
```

##### Testnet

```bash
rsk-cli resolve testing.rsk --testnet
```

Output example:

```
🔍 Resolving testing.rsk...
✅ Domain resolved successfully!
🏷️ Domain: testing.rsk
📄 Address: 0x0000000000000000000000000000000001000006
🌐 Network: Rootstock Mainnet
```

#### Reverse Resolution (Address to Domain)

Convert an address back to its RNS domain name:

##### Mainnet

```bash
rsk-cli resolve 0x123456789abcdef0123456789abcdef012345678 --reverse
```

##### Testnet

```bash
rsk-cli resolve 0x123456789abcdef0123456789abcdef012345678 --reverse --testnet
```

Output example:

```
🔍 Resolving address: 0x123456789abcdef0123456789abcdef012345678
✅ Resolution successful!
📍 Address: 0x123456789abcdef0123456789abcdef012345678
📌 Name: alice.rsk
🌐 Network: Rootstock Testnet
```

> **Note**:
> - The `.rsk` extension is automatically appended if not provided
> - Both checksummed and non-checksummed addresses are supported
> - The command will show appropriate error messages if the name or address cannot be resolved

## 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.
Expand Down
65 changes: 62 additions & 3 deletions bin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ import { bridgeCommand } from "../src/commands/bridge.js";
import { batchTransferCommand } from "../src/commands/batchTransfer.js";
import { historyCommand } from "../src/commands/history.js";
import { selectAddress } from "../src/commands/selectAddress.js";
import { resolveCommand } from "../src/commands/resolve.js";
import { transactionCommand } from "../src/commands/transaction.js";
import { parseEther } from "viem";
import { resolveRNSToAddress } from "../src/utils/rnsHelper.js";
import { validateAndFormatAddressRSK } from "../src/utils/index.js";

interface CommandOptions {
testnet?: boolean;
Expand All @@ -35,9 +38,11 @@ interface CommandOptions {
file?: string;
interactive?: boolean;
token?: Address;
reverse?: boolean;
gasLimit?: string;
gasPrice?: string;
data?: string;
rns?: string;
}

const orange = chalk.rgb(255, 165, 0);
Expand Down Expand Up @@ -73,10 +78,26 @@ 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")
.option("--rns <domain>", "Token holder RNS domain (e.g., alice.rsk)")
.action(async (options: CommandOptions) => {
let holderAddress = options.address;
if (options.rns) {
const resolvedAddress = await resolveRNSToAddress({
name: options.rns,
testnet: !!options.testnet,
isExternal: false
});
if (!resolvedAddress) {
throw new Error(`Failed to resolve RNS domain: ${options.rns}`);
}
holderAddress = resolvedAddress;
}

await balanceCommand({
testnet: !!options.testnet,
walletName: options.wallet!,
address: holderAddress,
});
});

Expand All @@ -86,6 +107,7 @@ program
.option("-t, --testnet", "Transfer on the testnet")
.option("--wallet <wallet>", "Name of the wallet")
.option("-a, --address <address>", "Recipient address")
.option("--rns <domain>", "Recipient RNS domain (e.g., alice.rsk)")
.option("--token <address>", "ERC20 token contract address (optional, for token transfers)")
.option("--value <value>", "Amount to transfer")
.option("-i, --interactive", "Execute interactively and input transactions")
Expand All @@ -112,9 +134,30 @@ program
throw new Error("Invalid value specified for transfer.");
}

const address = options.address
? (`0x${options.address.replace(/^0x/, "")}` as `0x${string}`)
: await selectAddress();
let address: `0x${string}`;
if (options.rns) {
const resolvedAddress = await resolveRNSToAddress({
name: options.rns,
testnet: !!options.testnet,
isExternal: false
});
if (!resolvedAddress) {
throw new Error(`Failed to resolve RNS domain: ${options.rns}`);
}
const formatted = validateAndFormatAddressRSK(resolvedAddress as string, !!options.testnet);
if (!formatted) {
throw new Error(`Invalid resolved address for domain: ${options.rns}`);
}
address = formatted as `0x${string}`;
} else if (options.address) {
const formatted = validateAndFormatAddressRSK(String(options.address), !!options.testnet);
if (!formatted) {
throw new Error("Invalid recipient address");
}
address = formatted as `0x${string}`;
} else {
address = await selectAddress();
}

const txOptions = {
...(options.gasLimit && { gasLimit: BigInt(options.gasLimit) }),
Expand Down Expand Up @@ -244,11 +287,13 @@ program
.option("-i, --interactive", "Execute interactively and input transactions")
.option("-t, --testnet", "Execute on the testnet")
.option("-f, --file <path>", "Execute transactions from a file")
.option("--rns", "Enable RNS domain resolution for recipient addresses")
.action(async (options) => {
try {
const interactive = !!options.interactive;
const testnet = !!options.testnet;
const file = options.file;
const resolveRNS = !!options.rns;

if (interactive && file) {
console.error(
Expand All @@ -263,6 +308,7 @@ program
filePath: file,
testnet: testnet,
interactive: interactive,
resolveRNS: resolveRNS,
});
} catch (error: any) {
console.error(
Expand All @@ -272,4 +318,17 @@ program
}
});

program
.command("resolve <name>")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we shoould call it just resolve?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it's just resolve

.description("Resolve RNS names to addresses or reverse lookup addresses to names")
.option("-t, --testnet", "Use testnet (currently mainnet only)")
.option("-r, --reverse", "Reverse lookup: address to name")
.action(async (name: string, options: CommandOptions) => {
await resolveCommand({
name,
testnet: !!options.testnet,
reverse: !!options.reverse
});
});

program.parse(process.argv);
Loading