Skip to content
This repository was archived by the owner on Mar 13, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,27 @@ rm ./examples/sample-key
tradetrust deploy document-store "My Name" --network sepolia --key 0000000000000000000000000000000000000000000000000000000000000003
```

### Providing custom RPC URLs

When interacting with the blockchain, you may want to connect to a different Ethereum provider than the default ones. All functions that interact with the blockchain support the `--rpc-url` option to specify a custom RPC endpoint:

1. Using `--rpc-url` option where you provide the URL of your custom Ethereum RPC provider.
2. When `--rpc-url` is provided, it takes precedence over the default network provider.
3. This is useful for connecting to private networks, custom providers, or alternative public endpoints.

Example:

```bash
# Using custom RPC URL with document store deployment
tradetrust deploy document-store "My Name" --network sepolia --rpc-url https://custom-rpc.example.com

# Using custom RPC URL with token registry operations
tradetrust deploy token-registry "My Registry" --network sepolia --rpc-url https://my-provider.com

# Using custom RPC URL with document store operations
tradetrust document-store issue --address 0x1234... --hash 0xabcd... --network sepolia --rpc-url https://custom-endpoint.io
```

### Providing the Remarks and Encryption Key

Enables users to attach encrypted remarks (up to 120 characters) to blockchain transactions. The encrypted remarks are stored immutably on the blockchain and can be viewed in the endorsement chain. This ensures secure and meaningful metadata is recorded alongside transactions.
Expand Down
73 changes: 40 additions & 33 deletions package-lock.json

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

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@
"@snyk/protect": "^1.1196.0",
"@tradetrust-tt/dnsprove": "^2.18.0",
"@tradetrust-tt/document-store": "^4.1.1",
"@tradetrust-tt/token-registry": "^5.2.0",
"@tradetrust-tt/tradetrust": "^6.10.0",
"@tradetrust-tt/tradetrust-config": "^1.19.0",
"@tradetrust-tt/tt-verify": "^9.5.0",
"@trustvc/trustvc": "^1.7.0",
"@tradetrust-tt/token-registry": "^5.5.0",
"@tradetrust-tt/tradetrust": "^6.10.2",
"@tradetrust-tt/tradetrust-config": "^1.19.1",
"@tradetrust-tt/tt-verify": "^9.5.1",
"@trustvc/trustvc": "^1.7.4",
"ajv": "^8.4.0",
"ajv-formats": "^2.1.0",
"chalk": "^4.1.2",
Expand Down
10 changes: 8 additions & 2 deletions src/__tests__/unwrap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ import wrappedFileFixture1 from "./fixture/2.0/wrapped-example.1.json";
import unwrappedFileFixture1 from "./fixture/2.0/unwrapped-example.1.json";
import wrappedFileFixture2 from "./fixture/2.0/wrapped-example.2.json";
import unwrappedFileFixture2 from "./fixture/2.0/unwrapped-example.2.json";

jest.mock("fs");
jest.mock("fs", () => {
return {
...jest.requireActual("fs"),
readdir: jest.fn(),
lstatSync: jest.fn(),
writeFileSync: jest.fn(),
};
});

describe("unwrap", () => {
describe("unwrapIndividualDocuments", () => {
Expand Down
9 changes: 8 additions & 1 deletion src/__tests__/wrap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ import { Output } from "../implementations/utils/disk";
import fs from "fs";
import { utils } from "@tradetrust-tt/tradetrust";

jest.mock("fs");
jest.mock("fs", () => {
return {
...jest.requireActual("fs"),
readdir: jest.fn(),
lstatSync: jest.fn(),
writeFileSync: jest.fn(),
};
});

describe("batchIssue", () => {
describe("appendProofToDocuments", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ exports[`get should return dns-txt 1`] = `
"netId": "1338",
"type": "openatts",
},
{
"addr": "0x94FD21A026E29E0686583b8be71Cb28a8ca1A8d4",
"dnssec": false,
"net": "ethereum",
"netId": "1338",
"type": "openatts",
},
{
"addr": "0xc98d993271a997384889dd39c14cec0c1e0206c2",
"dnssec": false,
Expand Down
17 changes: 16 additions & 1 deletion src/commands/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ export const isWalletOption = (option: any): option is WalletOption => {
return typeof option?.encryptedWalletPath === "string";
};

export type RpcUrlOption = {
rpcUrl: string;
};

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const isRpcUrlOption = (option: any): option is RpcUrlOption => {
return typeof option?.rpcUrl === "string";
};

export type WalletOrSignerOption = Partial<PrivateKeyOption> | Partial<AwsKmsSignerOption> | Partial<WalletOption>;

export interface GasPriceScale {
Expand Down Expand Up @@ -121,5 +130,11 @@ export const withAwsKmsSignerOption = (yargs: Argv): Argv =>
"AWS KMS key id. Example: arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab",
});

export const withRpcUrlOption = (yargs: Argv): Argv =>
yargs.option("rpc-url", {
type: "string",
description: "Custom RPC URL to connect to. Example: https://mainnet.infura.io/v3/YOUR-PROJECT-ID",
});

export const withNetworkAndWalletSignerOption = (yargs: Argv): Argv =>
withNetworkOption(withAwsKmsSignerOption(withWalletOption(withPrivateKeyOption(yargs))));
withNetworkOption(withRpcUrlOption(withAwsKmsSignerOption(withWalletOption(withPrivateKeyOption(yargs)))));
117 changes: 116 additions & 1 deletion src/implementations/deploy/document-store/document-store.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { deployDocumentStore } from "./document-store";
import { join } from "path";
import { Wallet } from "ethers";
import { Wallet, utils } from "ethers";
import { DocumentStoreFactory } from "@tradetrust-tt/document-store";
import { DeployDocumentStoreCommand } from "../../../commands/deploy/deploy.types";

Expand Down Expand Up @@ -104,5 +104,120 @@ describe("document-store", () => {
const addr = await passedSigner.getAddress();
expect(mockedDeploy.mock.calls[0][1]).toStrictEqual(addr);
});

describe("should use custom RPC URL", () => {
const createMockProvider = (chainId: number, name: string): any => ({
getNetwork: jest.fn().mockResolvedValue({ chainId, name }),
getBalance: jest.fn(),
getTransactionCount: jest.fn(),
getGasPrice: jest.fn(),
getFeeData: jest.fn().mockResolvedValue({
maxFeePerGas: utils.parseUnits("20", "gwei"),
maxPriorityFeePerGas: utils.parseUnits("2", "gwei"),
gasPrice: utils.parseUnits("20", "gwei"),
}),
estimateGas: jest.fn(),
call: jest.fn(),
sendTransaction: jest.fn(),
getBlock: jest.fn(),
getTransaction: jest.fn(),
getTransactionReceipt: jest.fn(),
getLogs: jest.fn(),
resolveName: jest.fn(),
lookupAddress: jest.fn(),
on: jest.fn(),
once: jest.fn(),
emit: jest.fn(),
listenerCount: jest.fn(),
listeners: jest.fn(),
off: jest.fn(),
removeAllListeners: jest.fn(),
addListener: jest.fn(),
removeListener: jest.fn(),
waitForTransaction: jest.fn(),
_isProvider: true,
});

it("should use custom RPC URL when provided with private key", async () => {
const customRpcUrl = "https://custom-rpc.example.com";
const mockProvider = createMockProvider(11155111, "sepolia");

// eslint-disable-next-line @typescript-eslint/no-var-requires
const { ethers: ethersModule } = require("ethers");
const jsonRpcProviderSpy = jest
.spyOn(ethersModule.providers, "JsonRpcProvider")
.mockImplementation(() => mockProvider);

await deployDocumentStore({
storeName: "Test",
network: "sepolia",
key: "0000000000000000000000000000000000000000000000000000000000000001",
rpcUrl: customRpcUrl,
dryRun: false,
maxPriorityFeePerGasScale: 1,
} as any);

const passedSigner: Wallet = mockedDocumentStoreFactory.mock.calls[0][0];
expect(passedSigner.privateKey).toBe("0x0000000000000000000000000000000000000000000000000000000000000001");
// Verify JsonRpcProvider was called with the custom RPC URL
expect(jsonRpcProviderSpy).toHaveBeenCalledWith(customRpcUrl);

jsonRpcProviderSpy.mockRestore();
});

it("should use custom RPC URL when provided with environment variable key", async () => {
process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002";
const customRpcUrl = "https://another-custom-rpc.example.com";
const mockProvider = createMockProvider(11155111, "sepolia");

// eslint-disable-next-line @typescript-eslint/no-var-requires
const { ethers: ethersModule } = require("ethers");
const jsonRpcProviderSpy = jest
.spyOn(ethersModule.providers, "JsonRpcProvider")
.mockImplementation(() => mockProvider);

await deployDocumentStore({
storeName: "Test",
network: "sepolia",
rpcUrl: customRpcUrl,
dryRun: false,
maxPriorityFeePerGasScale: 1,
} as any);

const passedSigner: Wallet = mockedDocumentStoreFactory.mock.calls[0][0];
expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`);
// Verify JsonRpcProvider was called with the custom RPC URL
expect(jsonRpcProviderSpy).toHaveBeenCalledWith(customRpcUrl);

jsonRpcProviderSpy.mockRestore();
});

it("should use custom RPC URL when provided with key file", async () => {
const customRpcUrl = "https://keyfile-custom-rpc.example.com";
const mockProvider = createMockProvider(11155111, "sepolia");

// eslint-disable-next-line @typescript-eslint/no-var-requires
const { ethers: ethersModule } = require("ethers");
const jsonRpcProviderSpy = jest
.spyOn(ethersModule.providers, "JsonRpcProvider")
.mockImplementation(() => mockProvider);

await deployDocumentStore({
storeName: "Test",
network: "sepolia",
keyFile: join(__dirname, "..", "..", "..", "..", "examples", "sample-key"),
rpcUrl: customRpcUrl,
dryRun: false,
maxPriorityFeePerGasScale: 1,
} as any);

const passedSigner: Wallet = mockedDocumentStoreFactory.mock.calls[0][0];
expect(passedSigner.privateKey).toBe("0x0000000000000000000000000000000000000000000000000000000000000003");
// Verify JsonRpcProvider was called with the custom RPC URL
expect(jsonRpcProviderSpy).toHaveBeenCalledWith(customRpcUrl);

jsonRpcProviderSpy.mockRestore();
});
});
});
});
Loading