Skip to content

Latest commit

 

History

History
186 lines (136 loc) · 5.62 KB

File metadata and controls

186 lines (136 loc) · 5.62 KB

Contributing to @veritix/contract-sdk

Thank you for helping build the VeriTix SDK! This document describes how to pick up a stub module and implement it correctly.


Table of Contents


Prerequisites

Tool Version
Node.js ≥ 20
npm ≥ 10
A Stellar Testnet account Stellar Laboratory

Development Setup

# 1. Fork and clone the repo
git clone https://github.com/veritix/contract-sdk.git
cd contract-sdk

# 2. Use the pinned Node.js version (.nvmrc)
nvm use

# 3. Install dependencies (run npm ci after nvm use)
npm ci

# 4. Copy the env example and fill in your values
cp .env.example .env

# 5. Build to verify the TypeScript compiles
npm run build

# 6. Run the existing test suite
npm test

Project Structure

src/
  client.ts          ← Main VeriTixClient class
  modules/           ← One file per contract feature area
  types/index.ts     ← Shared TypeScript interfaces (do not edit lightly)
  utils/
    errors.ts        ← VeriTixError + parseSorobanError
    network.ts       ← getTestnetConfig, getMainnetConfig, getHorizonUrl
    transaction.ts   ← buildContractCall, simulateTransaction, submitTransaction
  index.ts           ← Public barrel export
tests/               ← Jest test files mirroring src/modules/

Implementing a Module Stub

Each method in src/modules/*.ts currently contains a // TODO: implement comment and throws new Error('not implemented'). Here is the standard pattern to follow when implementing one:

1. Implement the transaction utils first

All write operations go through three utility functions that live in src/utils/transaction.ts:

buildContractCall  →  simulateTransaction  →  submitTransaction

These must be completed before module write methods can work.

2. Implement a read method

// Example: EscrowModule.getEscrow
async getEscrow(id: bigint): Promise<EscrowRecord | null> {
  const account = await this.server.getAccount(this.config.sourceAddress);
  const tx = await buildContractCall(
    this.server,
    account,
    this.config.contractId,
    'get_escrow',
    [nativeToScVal(id, { type: 'u64' })],
    this.config.networkPassphrase,
  );
  const { transaction } = await simulateTransaction(this.server, tx);
  // Parse the ScVal return value into an EscrowRecord
  // Return null if the contract returns void / None
  ...
}

3. Implement a write method

// Example: EscrowModule.createEscrow
async createEscrow(params: CreateEscrowParams): Promise<TransactionResult> {
  if (!this.keypair) throw new Error('keypair required for write operations');
  const account = await this.server.getAccount(this.keypair.publicKey());
  const tx = await buildContractCall(...);
  const { transaction } = await simulateTransaction(this.server, tx);
  return submitTransaction(this.server, transaction, this.keypair);
}

4. Wrap errors

Catch raw RPC errors and pass them through parseSorobanError:

} catch (err) {
  throw parseSorobanError(err);
}

Writing Tests

  • Tests live in tests/ and mirror src/modules/.
  • Each stub test already exists; replace the rejects.toThrow('not implemented') assertion with real expectations.
  • Use Jest mocks to avoid hitting the live network in unit tests.
  • Integration tests (hitting Testnet) should be placed in a separate tests/integration/ directory and skipped in CI unless INTEGRATION=true is set.

Run tests:

npm test               # unit tests only
npm test -- --watch    # watch mode

Code Style

  • Prettier handles formatting: npm run format
  • ESLint handles linting: npm run lint
  • All public API methods must have JSDoc comments with @param, @returns, and @throws tags.
  • Prefer bigint for token amounts and IDs; never use number for amounts.
  • Use _prefix for intentionally unused parameters (satisfies no-unused-vars).

Submitting a Pull Request

  1. Branch from main: git checkout -b feat/implement-token-module
  2. Implement and test your change.
  3. Update CHANGELOG.md — if your PR modifies any file under src/, you must add an entry under the [Unreleased] section. CI will fail the build if src/ changes are detected without a corresponding CHANGELOG.md update. Use the following format:
    ## [Unreleased]
    
    ### Added
    - Brief description of the new feature or fix (#PR-number)
    Use ### Added for new features, ### Fixed for bug fixes, ### Changed for non-breaking changes, and ### Removed for removed functionality.
  4. Run npm run build && npm test && npm run lint — all must pass.
  5. Open a PR against main with a clear description of what was implemented.
  6. Reference the relevant module in the PR title, e.g. feat(token): implement mint and burn.

Happy building! 🚀


Versioning with Changesets

This project uses Changesets for versioning and changelog generation.

  1. After making changes, run npm run changeset and follow the prompts.
  2. Commit the generated .changeset/*.md file alongside your code changes.
  3. When merged to main, the Changeset PR bot will open a "Version Packages" PR automatically.
  4. Merging that PR bumps versions and publishes to npm via the release workflow.