Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
164244e
feat(cli): add EAS attestation support to deploy, verify, and transfe…
Ad-Capital Nov 6, 2025
ceed00c
refactor(attestation): normalize console + spinner usage for MCP Serv…
Ad-Capital Dec 1, 2025
017e146
Merge branch 'main' of https://github.com/Ad-Capital/rsk-cli into Adrian
Ad-Capital Dec 1, 2025
13f5eb1
refactor(attestation): centralize attestation flow with shared handle…
Ad-Capital Dec 8, 2025
4e48651
feat(attestation): add transfer attestation support with password cap…
Ad-Capital Dec 12, 2025
cf06ce5
refactor(logger): replace local logging with centralized logger and s…
Ad-Capital Dec 12, 2025
f814640
refactor(logger): centralize logging + spinner usage across commands …
Ad-Capital Dec 13, 2025
f1db85c
feat(attestation): add viewer URLs and document deployment/verificati…
Ad-Capital Jan 5, 2026
aee15ef
docs(attestation)!: require user-provided schema UIDs for all attesta…
Ad-Capital Jan 11, 2026
dbb51c2
feat(attestations): add default schemas for testnet attestations
Ad-Capital Jan 19, 2026
ceaecef
Merge branch 'main' into Adrian
scguaquetam Jan 29, 2026
18a2cf5
feat(attestation): implement all three attestation types with registe…
Ad-Capital Feb 13, 2026
9190089
docs(attestation): update schema definitions and UIDs in ATTESTATIONS.md
Ad-Capital Feb 15, 2026
b8e27df
refactor(walletSigner): remove unused viem WalletClient import
Ad-Capital Feb 17, 2026
6ad775f
fix(attestation): correct explorer URL to include /ras/ path
Ad-Capital Feb 17, 2026
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
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,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 command now supports RNS domain resolution for recipient addresses.
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 and on-chain attestations via the Ethereum Attestation Service (EAS).

#### Interactive Mode

Expand Down Expand Up @@ -360,6 +360,8 @@ The transfer command supports the following options:
- `--wallet`: Select a specific wallet to use
- `--gas-limit`: Custom gas limit for the transaction
- `--data`: Custom transaction data (hexadecimal format)
- `--attest-transfer`: Create on-chain attestation for the transfer
- `--attest-reason`: Reason for the transfer (used in attestation)

> **Note**: Before making any transfer, ensure you have:
> 1. A wallet configured with sufficient balance (RBTC or ERC20 tokens)
Expand All @@ -368,6 +370,17 @@ The transfer command supports the following options:
> 4. Enough RBTC to cover gas fees
> 5. Appropriate gas parameters for your transaction type

#### Attestations

Transfer attestations provide cryptographic proof of transfers on-chain using the Ethereum Attestation Service. On testnet, simply add the `--attest-transfer` flag to create an attestation automatically:

```bash
# Transfer with attestation
rsk-cli transfer --testnet --address 0x... --value 0.001 --attest-transfer --attest-reason "Payment for services"
```

For more information on attestations, including deployment and verification attestations, see [docs/ATTESTATIONS.md](docs/ATTESTATIONS.md).

### 4. Check Transaction Status

The `tx` command allows you to check the status of a specific transaction on the Rootstock blockchain by providing the transaction ID. You can check the status on either the mainnet or testnet using the appropriate flags.
Expand Down
65 changes: 44 additions & 21 deletions bin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { txCommand } from "../src/commands/tx.js";
import figlet from "figlet";
import chalk from "chalk";
import { deployCommand } from "../src/commands/deploy.js";
import { logError } from "../src/utils/logger.js";
import { verifyCommand } from "../src/commands/verify.js";
import { ReadContract } from "../src/commands/contract.js";
import { Address } from "viem";
Expand Down Expand Up @@ -52,6 +53,12 @@ interface CommandOptions {
gasLimit?: string;
gasPrice?: string;
data?: string;
attestDeployment?: boolean;
attestVerification?: boolean;
attestTransfer?: boolean;
attestSchemaUid?: string;
attestRecipient?: string;
attestReason?: string;
rns?: string;
}

Expand Down Expand Up @@ -124,12 +131,22 @@ program
.option("--gas-limit <limit>", "Custom gas limit")
.option("--gas-price <price>", "Custom gas price in RBTC")
.option("--data <data>", "Custom transaction data (hex)")
.option("--attest-transfer", "Create attestation for significant transfers")
.option("--attest-schema-uid <uid>", "Custom schema UID for attestation")
.option("--attest-recipient <address>", "Custom recipient for attestation (default: transfer recipient)")
.option("--attest-reason <reason>", "Reason/purpose for the transfer (e.g., 'Grant payment', 'Bounty reward')")
.action(async (options: CommandOptions) => {
try {
if (options.interactive) {
await batchTransferCommand({
testnet: !!options.testnet,
interactive: true,
attestation: {
enabled: !!options.attestTransfer,
schemaUID: options.attestSchemaUid,
recipient: options.attestRecipient,
reason: options.attestReason
}
});
return;
}
Expand Down Expand Up @@ -182,13 +199,16 @@ program
value: value,
name: options.wallet!,
tokenAddress: options.token as `0x${string}` | undefined,
attestation: {
enabled: !!options.attestTransfer,
schemaUID: options.attestSchemaUid,
recipient: options.attestRecipient,
reason: options.attestReason
}
}
);
} catch (error: any) {
console.error(
chalk.red("Error during transfer:"),
error.message || error
);
logError(false, `Error during transfer: ${error.message || error}`);
}
});

Expand Down Expand Up @@ -221,6 +241,9 @@ program
.option("--wallet <wallet>", "Name of the wallet")
.option("--args <args...>", "Constructor arguments (space-separated)")
.option("-t, --testnet", "Deploy on the testnet")
.option("--attest-deployment", "Create attestation for deployment")
.option("--attest-schema-uid <uid>", "Custom schema UID for attestation")
.option("--attest-recipient <address>", "Custom recipient for attestation (default: contract address)")
.action(async (options: CommandOptions) => {
const args = options.args || [];
await deployCommand(
Expand All @@ -230,6 +253,11 @@ program
testnet: options.testnet,
args: args,
name: options.wallet!,
attestation: {
enabled: !!options.attestDeployment,
schemaUID: options.attestSchemaUid,
recipient: options.attestRecipient
}
}
);
});
Expand All @@ -245,6 +273,9 @@ program
"--decodedArgs <args...>",
"Decoded Constructor arguments (space-separated)"
)
.option("--attest-verification", "Create attestation for contract verification")
.option("--attest-schema-uid <uid>", "Custom schema UID for attestation")
.option("--attest-recipient <address>", "Custom recipient for attestation (default: contract address)")
.action(async (options: CommandOptions) => {
const args = options.decodedArgs || [];
await verifyCommand(
Expand All @@ -254,6 +285,11 @@ program
name: options.name!,
testnet: options.testnet === undefined ? undefined : !!options.testnet,
args: args,
attestation: {
enabled: !!options.attestVerification,
schemaUID: options.attestSchemaUid,
recipient: options.attestRecipient
}
}
);
});
Expand Down Expand Up @@ -311,11 +347,7 @@ program
const resolveRNS = !!options.rns;

if (interactive && file) {
console.error(
chalk.red(
"🚨 Cannot use both interactive mode and file input simultaneously."
)
);
logError(false, "Cannot use both interactive mode and file input simultaneously.");
return;
}

Expand All @@ -326,10 +358,7 @@ program
resolveRNS: resolveRNS,
});
} catch (error: any) {
console.error(
chalk.red("🚨 Error during batch transfer:"),
chalk.yellow(error.message || "Unknown error")
);
logError(false, `Error during batch transfer: ${error.message || "Unknown error"}`);
}
});

Expand Down Expand Up @@ -379,10 +408,7 @@ program
}
);
} catch (error: any) {
console.error(
chalk.red("Error during transaction:"),
error.message || error
);
logError(false, `Error during transaction: ${error.message || error}`);
}
});

Expand Down Expand Up @@ -427,10 +453,7 @@ program
isExternal: false
});
} catch (error: any) {
console.error(
chalk.red("Error during monitoring:"),
error.message || error
);
logError(false, `Error during monitoring: ${error.message || error}`);
}
});

Expand Down
191 changes: 191 additions & 0 deletions docs/ATTESTATIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# Attestations Feature

The RSK CLI supports creating on-chain attestations for transfers using the Ethereum Attestation Service (EAS) deployed on Rootstock.

## Overview

Attestations provide cryptographic proof and additional metadata about blockchain transactions. They are stored on-chain and can be queried and verified by anyone.

## RSK EAS Contract Addresses

### Testnet
- EAS Contract: `0xc300aeEaDd60999933468738c9F5D7e9C0671e1c`
- Schema Registry: `0x679c62956cD2801AbAbF80e9D430f18859Eea2d5`

### Mainnet
- EAS Contract: `0x54C0726E9d2D57Bc37AD52c7E219A3229e0eE963`
- Schema Registry: `0xeF29675d82CC5967069d6d9C17F2719f67728F5B`

## Usage

### Transfer Attestations

Create attestations when transferring RBTC or tokens on testnet:

```bash
# Interactive transfer with attestation
node dist/bin/index.js transfer --testnet -i --attest-transfer

# Direct transfer with attestation
node dist/bin/index.js transfer \
--testnet \
--address 0x... \
--value 0.001 \
--attest-transfer \
--attest-reason "Payment for services"

# Token transfer with attestation
node dist/bin/index.js transfer \
--testnet \
--token 0x... \
--address 0x... \
--value 10 \
--attest-transfer
```

### Deployment Attestations

Create attestations when deploying contracts:

```bash
node dist/bin/index.js deploy \
--testnet \
--abi path/to/abi.json \
--bytecode 0x... \
--attest-deployment
```

### Verification Attestations

Create attestations when verifying contracts:

```bash
node dist/bin/index.js verify \
--testnet \
--contract 0x... \
--attest-verification
```

## CLI Options

| Option | Description |
|--------|-------------|
| `--attest-transfer` | Enable attestation for transfers |
| `--attest-deployment` | Enable attestation for deployments |
| `--attest-verification` | Enable attestation for verifications |
| `--attest-schema-uid <UID>` | Custom schema UID (optional on testnet, required on mainnet) |
| `--attest-recipient <address>` | Custom attestation recipient (optional) |
| `--attest-reason <text>` | Reason for transfer (optional) |

## Schema Information

### Testnet Default Schemas

Testnet has pre-registered default schemas for all attestation types. You can use attestations without specifying a schema UID:

- **Transfer Schema UID**: `0x0da2422c401f8810a6be8f4451aaa0c0a5a6601701cba17bba14f50bb0039dc8`
- **Deployment Schema UID**: `0xac72a47948bf42cad950de323c51a0033346629ae4a42da45981ae9748118a72`
- **Verification Schema UID**: `0xdf68ba5414a61a12f26d41df4f5a1ef3ffe2ab809fea94d9c76fa7cb84b8fb4a`

### Mainnet Schemas

Mainnet currently has no default schemas. You must register your own schema and provide its UID using `--attest-schema-uid <UID>`.

### Transfer Schema

**Schema Definition:**
```
address sender,address recipient,string amount,address tokenAddress,string tokenSymbol,bytes32 transactionHash,uint256 blockNumber,uint256 timestamp,string reason,string transferType,string version
```

**Description:**
- `sender`: Address that sent the transfer
- `recipient`: Address that received the transfer
- `amount`: Amount transferred (as string to preserve precision)
- `tokenAddress`: Address of the token contract (0x0 for RBTC)
- `tokenSymbol`: Symbol of the token (e.g., "RBTC", "RIF")
- `transactionHash`: Transaction hash of the transfer
- `blockNumber`: Block number when the transfer occurred
- `timestamp`: Unix timestamp of the transfer
- `reason`: Optional reason for the transfer
- `transferType`: Type of transfer (e.g., "RBTC", "ERC20")
- `version`: Schema version identifier (e.g., "1.0")

### Deployment Schema

**Schema Definition:**
```
string contractName,address contractAddress,address deployer,uint256 blockNumber,bytes32 transactionHash,uint256 timestamp,string abiHash,string bytecodeHash,string version
```

**Description:**
- `contractName`: Name of the deployed contract
- `contractAddress`: Address where the contract was deployed
- `deployer`: Address that deployed the contract
- `blockNumber`: Block number when the contract was deployed
- `transactionHash`: Transaction hash of the deployment
- `timestamp`: Unix timestamp of the deployment
- `abiHash`: Keccak256 hash of the contract ABI
- `bytecodeHash`: Keccak256 hash of the contract bytecode
- `version`: Schema version identifier (e.g., "1.0")

### Verification Schema

**Schema Definition:**
```
string contractName,address contractAddress,address verifier,string sourceCodeHash,string compilationTarget,string compilerVersion,bool optimizationUsed,uint256 timestamp,string verificationTool,string version,string schemaVersion
```

**Description:**
- `contractName`: Name of the verified contract
- `contractAddress`: Address of the verified contract
- `verifier`: Address that performed the verification
- `sourceCodeHash`: Hash of the verified source code
- `compilationTarget`: Compilation target (e.g., "contracts/MyContract.sol:MyContract")
- `compilerVersion`: Solidity compiler version used
- `optimizationUsed`: Whether optimization was enabled during compilation
- `timestamp`: Unix timestamp of the verification
- `verificationTool`: Tool used for verification (e.g., "rsk-cli")
- `version`: Schema version identifier (e.g., "1.0")
- `schemaVersion`: Schema revision identifier (e.g., "2.0")

## How to Register Schemas (Mainnet Only)

For mainnet deployments, you must register schemas before creating attestations. Schema registration is an on-chain operation that requires RBTC for gas fees.

### Using EAS Scan

1. Visit [https://easscan.org/schema/create](https://easscan.org/schema/create)

2. Connect your wallet and select the Rootstock network

3. Enter your schema definition using one of the structures documented above

4. Set revocable to `true` (recommended for flexibility)

5. Submit the transaction (you'll need RBTC for gas fees)

6. Copy the returned Schema UID

7. Use the Schema UID with the `--attest-schema-uid` flag when creating attestations

### Using the Schema Registry Contract Directly

Alternatively, you can interact directly with the Schema Registry contract at `0xeF29675d82CC5967069d6d9C17F2719f67728F5B`.

## MCP Server Integration

When using this CLI as an MCP server, attestations are fully supported with automatic logging suppression for clean JSON responses.

## Resources

- [Rootstock Attestation Service Documentation](https://dev.rootstock.io/dev-tools/attestations/ras/)
- [Ethereum Attestation Service](https://docs.attest.org/)
- [RSK Explorer](https://explorer.rootstock.io/)

## Notes

- Testnet uses default schemas - no schema UID required
- Mainnet requires schema registration and the `--attest-schema-uid` flag
- All attestations incur additional gas costs
- Attestations are permanent and immutable on-chain
Loading
Loading