Skip to content

feat: generate TypeScript bindings for Soroban smart contracts#517

Open
Josue19-08 wants to merge 4 commits intoboundlessfi:mainfrom
Josue19-08:feat/soroban-contract-bindings
Open

feat: generate TypeScript bindings for Soroban smart contracts#517
Josue19-08 wants to merge 4 commits intoboundlessfi:mainfrom
Josue19-08:feat/soroban-contract-bindings

Conversation

@Josue19-08
Copy link
Copy Markdown
Contributor

@Josue19-08 Josue19-08 commented Mar 27, 2026

Description

Implements on-chain read and transaction-building capabilities for the frontend by generating TypeScript client bindings for the four core Soroban contracts.

@stellar/stellar-sdk was already present as a dependency — this PR wires it up for direct Soroban contract interaction.

Changes

  • Generated bindings via stellar contract bindings typescript for all 4 contracts into lib/contracts/<contract-name>/:
    • bounty-registry — Bounty CRUD, applications, submissions, approvals
    • core-escrow — Fund pools, release slots, fee calculation
    • reputation-registry — Spark Credits, reputation scoring
    • project-registry — Project details for bounty sponsors
  • lib/contracts/index.ts — Client factories (createBountyRegistryClient, createCoreEscrowClient, createReputationRegistryClient, createProjectRegistryClient) with environment-based address config and network-aware RPC URLs (testnet / mainnet)
  • lib/contracts/transaction.ts — Helpers: simulateContract<T>, buildTransaction (returns unsigned XDR for wallet signing), submitTransaction (polls until confirmed)
  • .env.example — Added NEXT_PUBLIC_*_CONTRACT_ID vars for all 4 contracts with testnet defaults

Acceptance Criteria

  • TypeScript bindings generated for all 4 contracts
  • Read-only queries work via simulateContract (e.g. get_bounty, get_application)
  • Unsigned transaction building works for write methods via buildTransaction
  • Contract addresses configurable via environment variables
  • Types properly exported and usable in hooks/components
  • npm run type-check passes
  • npm run build passes

Closes

Closes #139

Summary by CodeRabbit

  • New Features

    • Added client libraries for Bounty Registry, Core Escrow, Reputation Registry, and Project Registry.
    • Added contract transaction utilities for simulating, building, and submitting transactions.
    • Exposed network configuration and four new NEXT_PUBLIC_* env vars for contract addresses (testnet defaults + mainnet override notes).
  • Documentation

    • Added usage READMEs for each contract library with generation/publish guidance.
  • Chores

    • Added package manifests, TypeScript build configs, and updated ignore rules for generated artifacts.

Generate TypeScript client bindings for all 4 core Soroban contracts
(Bounty Registry, Core Escrow, Reputation Registry, Project Registry)
using the stellar CLI. Add lib/contracts/index.ts with configured client
factories (environment-based address config, network-aware RPC URLs) and
lib/contracts/transaction.ts with simulateContract, buildTransaction, and
submitTransaction helpers. Update .env.example with contract address vars.
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 27, 2026

@Josue19-08 is attempting to deploy a commit to the Threadflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 27, 2026

📝 Walkthrough

Walkthrough

Adds four generated TypeScript Soroban contract client packages (bounty-registry, core-escrow, reputation-registry, project-registry), a central contracts entrypoint and transaction helpers, and four NEXT_PUBLIC_* env vars for contract addresses (testnet defaults with mainnet override guidance).

Changes

Cohort / File(s) Summary
Environment Configuration
\.env.example
Added four NEXT_PUBLIC_*_CONTRACT_ID variables with testnet-default addresses and mainnet override guidance.
Bounty Registry Package
lib/contracts/bounty-registry/src/index.ts, lib/contracts/bounty-registry/package.json, lib/contracts/bounty-registry/tsconfig.json, lib/contracts/bounty-registry/README.md, lib/contracts/bounty-registry/.gitignore
New generated TypeScript client: exports types, errors, Client class with method bindings and deploy, package metadata, build config, README, and gitignore.
Core Escrow Package
lib/contracts/core-escrow/src/index.ts, lib/contracts/core-escrow/package.json, lib/contracts/core-escrow/tsconfig.json, lib/contracts/core-escrow/README.md, lib/contracts/core-escrow/.gitignore
New generated TypeScript client: escrow types, Client class with deploy and fromJSON mappings, package manifest, build config, README, and gitignore.
Reputation Registry Package
lib/contracts/reputation-registry/src/index.ts, lib/contracts/reputation-registry/package.json, lib/contracts/reputation-registry/tsconfig.json, lib/contracts/reputation-registry/README.md, lib/contracts/reputation-registry/.gitignore
New generated TypeScript client: reputation types, Client class and method bindings, package manifest, build config, README, and gitignore.
Project Registry Package
lib/contracts/project-registry/src/index.ts, lib/contracts/project-registry/package.json, lib/contracts/project-registry/tsconfig.json, lib/contracts/project-registry/README.md, lib/contracts/project-registry/.gitignore
New generated TypeScript client: project types, Client class with deploy and method mappings, package manifest, build config, README, and gitignore.
Contracts Index / Factories
lib/contracts/index.ts
New central module re-exporting bindings, resolves RPC URL and network passphrase from NEXT_PUBLIC_STELLAR_NETWORK, reads NEXT_PUBLIC_* contract envs (fails on missing mainnet values), and provides factory functions to create typed clients.
Transaction Utilities
lib/contracts/transaction.ts
Added simulateContract, buildTransaction, and submitTransaction helpers (simulation, unsigned XDR generation, signed submission with polling) and SubmitTransactionResult type.

Sequence Diagram(s)

sequenceDiagram
    participant ClientCode as Client
    participant ContractsModule as ContractsIndex
    participant RPC as SorobanRPC
    participant Network as StellarNetwork

    ClientCode->>ContractsModule: createXClient(publicKey?)
    ClientCode->>ContractsModule: getRpcUrl(), getNetworkPassphrase()
    ClientCode->>ContractsModule: client.method(...)\nreturns AssembledTransaction
    ClientCode->>ContractsModule: simulateContract(tx)
    ContractsModule->>RPC: /simulate (tx)
    RPC-->>ContractsModule: simulation result
    ContractsModule-->>ClientCode: decoded simulation result
    ClientCode->>ContractsModule: buildTransaction(tx)
    ContractsModule->>RPC: /simulate (populate)
    RPC-->>ContractsModule: populated tx metadata
    ContractsModule-->>ClientCode: unsigned XDR
    ClientCode->>Network: sign XDR (external wallet)
    ClientCode->>ContractsModule: submitTransaction(signedXdr)
    ContractsModule->>RPC: /send (signedXdr)
    RPC-->>ContractsModule: submission response (hash/status)
    ContractsModule->>RPC: /getTransaction(hash) [poll until found]
    RPC-->>ContractsModule: final transaction result
    ContractsModule-->>ClientCode: SubmitTransactionResult (hash + response)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Poem

"🐇 I hopped through code and stitched each binding seam,
Four contracts now hum in TypeScript dream,
RPCs and transactions join the dance,
Env vars set — the clients prance,
Hop on, sign, and let the ledgers beam!"

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR closes #139 which requires implementing a Milestone Submission Flow UI per Figma designs. However, the actual changes generate Soroban contract TypeScript bindings with no UI components, milestone submission modal/page implementation, shadcn components, or BoundlessSheet/BoundlessButton usage. This PR appears to address infrastructure needs (#517 per PR summary) unrelated to #139's UI requirements. Verify the correct linked issue or ensure milestone submission UI components are included in this PR.
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title accurately describes the main change: generating TypeScript bindings for Soroban smart contracts, which is the core focus of all changes across multiple contract directories.
Out of Scope Changes check ✅ Passed All changes are coherent with contract binding generation: contract type definitions, client factories, transaction helpers, environment configuration, and tooling setup (.gitignore, tsconfig, package.json files) for the four Soroban contracts.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 12

🧹 Nitpick comments (14)
lib/contracts/project-registry/.gitignore (1)

1-2: Include dist/ in .gitignore for this package.

Current ignore rules miss the compiled output directory used by TypeScript builds.

Proposed change
 node_modules/
 out/
+dist/
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/project-registry/.gitignore` around lines 1 - 2, Add the
compiled output directory to this package's ignore rules: update the .gitignore
in the project-registry package to include "dist/" (alongside existing entries
like "node_modules/" and "out/") so TypeScript build artifacts are not
committed; ensure the entry uses a trailing slash ("dist/") to clearly ignore
the directory.
.env.example (2)

34-38: Avoid dual sources of truth for contract ID defaults.

These values are duplicated in lib/contracts/index.ts (Lines 31-46). Keeping defaults in both places can drift over time; prefer a single canonical default source and keep the other as documentation/placeholders.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.env.example around lines 34 - 38, The .env.example currently hardcodes
NEXT_PUBLIC_BOUNTY_REGISTRY_CONTRACT_ID, NEXT_PUBLIC_CORE_ESCROW_CONTRACT_ID,
NEXT_PUBLIC_REPUTATION_REGISTRY_CONTRACT_ID, and
NEXT_PUBLIC_PROJECT_REGISTRY_CONTRACT_ID which duplicate defaults defined in
lib/contracts/index.ts; pick one canonical source for those default contract IDs
(prefer lib/contracts/index.ts as the runtime/default source) and remove the
hardcoded defaults from .env.example (leave placeholder keys or comment
indicating they are defined in lib/contracts/index.ts), or alternatively move
the canonical defaults into .env.example and have lib/contracts/index.ts read
from process.env; update references to NEXT_PUBLIC_* keys accordingly so only
one place holds the truth.

38-38: Add a trailing newline to satisfy dotenv linting.

Minor file-hygiene fix to clear the EndingBlankLine warning.

Proposed change
 NEXT_PUBLIC_PROJECT_REGISTRY_CONTRACT_ID="CCG4QM2GZKBN7GBRAE3PFNE3GM2B6QRS7FOKLHGV2FT2HHETIS7JUVYT"
+
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.env.example at line 38, The file ends without a trailing newline causing
dotenv lint warnings; edit .env.example so the final line (the declaration
NEXT_PUBLIC_PROJECT_REGISTRY_CONTRACT_ID="CCG4QM2GZKBN7GBRAE3PFNE3GM2B6QRS7FOKLHGV2FT2HHETIS7JUVYT")
is followed by a single trailing newline (i.e., an empty line at EOF) and commit
that change.
lib/contracts/reputation-registry/.gitignore (1)

1-2: Add dist/ to ignore rules for generated build output.

This package ignores node_modules/ and out/, but misses dist/, which is the expected TypeScript build output folder.

Proposed change
 node_modules/
 out/
+dist/
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/reputation-registry/.gitignore` around lines 1 - 2, The
.gitignore in the reputation-registry package is missing the TypeScript build
output folder; update the .gitignore (currently containing "node_modules/" and
"out/") to also include "dist/" so generated build artifacts are ignored; add a
new line with dist/ alongside the existing entries in the same file.
lib/contracts/bounty-registry/.gitignore (1)

1-2: Ignore dist/ artifacts in this package as well.

node_modules/ and out/ are ignored, but TypeScript output is typically emitted to dist/ in these generated contract packages.

Proposed change
 node_modules/
 out/
+dist/
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/bounty-registry/.gitignore` around lines 1 - 2, Update the
package .gitignore to also ignore TypeScript build artifacts by adding the
"dist/" pattern alongside the existing "node_modules/" and "out/" entries;
modify the bounty-registry package .gitignore to include a new line with "dist/"
so compiled output is not committed.
lib/contracts/core-escrow/.gitignore (1)

1-2: Add dist/ to ignored paths.

This avoids tracking generated JavaScript/declaration artifacts from package builds.

Proposed change
 node_modules/
 out/
+dist/
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/core-escrow/.gitignore` around lines 1 - 2, The .gitignore
currently lists node_modules/ and out/ but omits dist/, so add the dist/ entry
to the file to ensure build output (generated JavaScript and declaration files)
is not committed; update the file named core-escrow .gitignore by appending a
single line "dist/" (matching the style of existing entries) so that generated
artifacts from package builds are ignored alongside node_modules/ and out/.
lib/contracts/bounty-registry/package.json (1)

12-12: Use caret version range for the buffer dependency.

The exact pin "6.0.3" prevents patch updates and can cause dependency resolution conflicts. Change to "^6.0.3" to allow compatible updates.

📦 Proposed fix
-    "buffer": "6.0.3"
+    "buffer": "^6.0.3"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/bounty-registry/package.json` at line 12, The dependency
"buffer" in package.json is pinned to an exact version "6.0.3"; update the
version string to a caret range "^6.0.3" so patch/minor compatible updates are
allowed and to reduce dependency resolution conflicts—edit the "buffer" entry in
lib/contracts/bounty-registry/package.json to use "^6.0.3" instead of "6.0.3".
lib/contracts/project-registry/package.json (1)

12-12: Use caret version range for the buffer dependency.

The buffer package is pinned to exactly 6.0.3 without a caret (^). This prevents npm from resolving patch and minor updates, which can lead to dependency conflicts in consuming projects if other packages require a newer patch version of buffer.

Consider changing to "buffer": "^6.0.3" to allow compatible updates.

📦 Proposed fix
-    "buffer": "6.0.3"
+    "buffer": "^6.0.3"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/project-registry/package.json` at line 12, The package.json
currently pins the buffer dependency to an exact version ("buffer": "6.0.3");
change it to a caret range so npm can install compatible minor/patch updates by
updating the dependency value to "buffer": "^6.0.3" in the
lib/contracts/project-registry package.json (look for the "buffer" entry in
dependencies).
lib/contracts/reputation-registry/tsconfig.json (2)

72-74: Consider enabling full strict mode instead of only strictNullChecks.

Currently only strictNullChecks is enabled (line 74). Enabling the full "strict": true option provides stronger type safety by activating all strict type-checking flags together (noImplicitAny, strictFunctionTypes, strictBindCallApply, etc.), which helps catch more potential bugs at compile time.

🔒 Proposed enhancement
   /* Type Checking */
-  // "strict": true, /* Enable all strict type-checking options. */
+  "strict": true, /* Enable all strict type-checking options. */
   // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */
-  "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */,
+  // "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/reputation-registry/tsconfig.json` around lines 72 - 74, Enable
full TypeScript strict mode by setting "strict": true in tsconfig.json and
removing or un-commenting the individual flags (e.g., the commented "strict" and
"noImplicitAny") so that the compiler enables all strict checks instead of only
"strictNullChecks"; update the config entry that currently has
"strictNullChecks": true to either replace it with "strict": true or add
"strict": true alongside it to ensure flags like noImplicitAny,
strictFunctionTypes, strictBindCallApply, etc. are active.

66-66: Consider enabling isolatedModules for better bundler compatibility.

The isolatedModules option is currently commented out. Enabling it ensures each file can be transpiled independently, which is important for compatibility with modern bundlers (like Next.js's bundler) and can catch certain TypeScript features that don't work well in isolated compilation scenarios.

⚙️ Proposed enhancement
   /* Interop Constraints */
-  // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
+  "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/reputation-registry/tsconfig.json` at line 66, Enable the
TypeScript "isolatedModules" option in the tsconfig by uncommenting and setting
"isolatedModules": true so each file can be transpiled independently for better
bundler compatibility; locate the "isolatedModules" entry in tsconfig.json (the
line currently commented as // "isolatedModules": true) and restore it as an
active compiler option.
lib/contracts/bounty-registry/tsconfig.json (2)

72-74: Consider enabling full strict mode instead of only strictNullChecks.

Enable "strict": true (line 72) to activate all strict type-checking options for better type safety. This is preferable to enabling individual strict flags piecemeal.

🔒 Proposed enhancement
   /* Type Checking */
-  // "strict": true, /* Enable all strict type-checking options. */
+  "strict": true, /* Enable all strict type-checking options. */
   // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */
-  "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */,
+  // "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/bounty-registry/tsconfig.json` around lines 72 - 74, Enable
full TypeScript strict mode by setting the "strict" compiler option to true
(uncomment or add the "strict": true key) instead of only relying on
"strictNullChecks"; keep or remove the individual flags as needed (TypeScript
will derive them from "strict") so update the tsconfig entry where
"strictNullChecks" and the commented "strict" appear to ensure "strict": true is
present and consistent with "strictNullChecks".

66-66: Consider enabling isolatedModules for better bundler compatibility.

Enabling isolatedModules ensures compatibility with modern bundlers and can help catch issues earlier in the development process.

⚙️ Proposed enhancement
   /* Interop Constraints */
-  // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
+  "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/bounty-registry/tsconfig.json` at line 66, Uncomment or add
"isolatedModules": true inside the tsconfig's compilerOptions (the
"isolatedModules" flag) so the project is compiled per-file for bundler
compatibility; update the tsconfig.json to set that option to true and run the
type/build tests to ensure no code patterns (e.g., const enums or non-isolated
constructs) need adjusting.
lib/contracts/core-escrow/package.json (1)

12-12: Use caret version range for the buffer dependency.

Change from exact "6.0.3" to "^6.0.3" to allow compatible patch updates.

📦 Proposed fix
-    "buffer": "6.0.3"
+    "buffer": "^6.0.3"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/core-escrow/package.json` at line 12, Update the buffer
dependency in package.json from the fixed version "6.0.3" to a caret range so
compatible patch/minor updates are allowed; locate the "buffer" entry in
lib/contracts/core-escrow/package.json and change its version string to "^6.0.3"
(ensuring the JSON remains valid).
lib/contracts/index.ts (1)

13-14: Expose the other generated bindings from the central entrypoint too.

lib/contracts currently forwards the bounty bindings only. That means named exports from core escrow, reputation, and project registry still require deep imports, which undercuts this file as the single contracts entrypoint.

♻️ Suggested namespaced re-exports
 export * from './bounty-registry/src/index';
+export * as coreEscrowBindings from './core-escrow/src/index';
+export * as reputationRegistryBindings from './reputation-registry/src/index';
+export * as projectRegistryBindings from './project-registry/src/index';
 export * from './transaction';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/index.ts` around lines 13 - 14, The central contracts
entrypoint currently only re-exports './bounty-registry/src/index' and
'./transaction', so generated bindings for core escrow, reputation, and project
registry remain available only via deep imports; update lib/contracts/index.ts
to also export the generated modules for those bindings (e.g., add export * from
'./core-escrow/src/index'; export * from './reputation/src/index'; export * from
'./project-registry/src/index' or appropriate module names used in the repo) so
consumers can import all contract bindings from this single entrypoint (or
alternatively provide namespaced re-exports if you prefer grouping).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/contracts/bounty-registry/package.json`:
- Line 5: The package.json "exports" currently points to "./dist/index.js" but
the consumer in lib/contracts/index.ts appears to import the source module
directly, so the compiled dist output is never used; either change the consumer
imports in lib/contracts/index.ts (and any other consumers) to import the
package root so Node/resolver picks up the "exports" (thus using the built
./dist/index.js), or change the package.json "exports" to point at the source
entry used by consumers (e.g., the src index) so imports continue to resolve to
source—update whichever side you choose so import paths and the "exports" field
consistently reference the same entry point.

In `@lib/contracts/bounty-registry/README.md`:
- Line 47: The README example references networks.futurenet but the project uses
testnet; update the example to use networks.testnet and ensure it matches the
exported symbol networks (verify the export named networks that contains
testnet) so the example aligns with the codebase and generation/PR notes.

In `@lib/contracts/bounty-registry/tsconfig.json`:
- Line 47: The build outputs to "outDir": "./dist" but consumers may be
importing source files (see lib/contracts/index.ts importing
"./bounty-registry/src/index") while package.json points to "./dist/index.js";
fix by aligning imports/exports: update lib/contracts/index.ts to import the
built artifact (e.g., from "./bounty-registry/dist/index" or "./bounty-registry"
if package.json main/exports point there) or change package.json/tsconfig so the
published entry matches the source import; ensure the unique symbols affected
are the tsconfig.json outDir setting, package.json exports "./dist/index.js",
and the import in lib/contracts/index.ts.

In `@lib/contracts/core-escrow/package.json`:
- Line 5: The package.json "exports" entry points to "./dist/index.js" but the
project and consumers appear to import source files directly (e.g.,
"./core-escrow/src/index"), leaving the dist build unused; either change the
"exports" value to point to the actual consumed entry (or remove it) or update
the build pipeline and consumers to compile and import from the dist output.
Locate the "exports" field in package.json and either update it to the correct
entrypoint that consumers use or ensure a build step produces ./dist/index.js
and update import paths in consuming code to reference the packaged entry;
finally run the build and verify consumers import the packaged entry instead of
source.

In `@lib/contracts/core-escrow/README.md`:
- Line 47: The README example is inconsistent: it references networks.futurenet
while the project uses testnet elsewhere; update the example to use the actual
exported constant from src/index.ts (e.g., replace networks.futurenet with
networks.testnet) or, if you intend to keep futurenet, update the generation
command and other examples to match; verify the exported symbol name "networks"
in src/index.ts and make the README example match that exact exported property.

In `@lib/contracts/index.ts`:
- Around line 33-46: CONTRACT_ADDRESSES currently hardcodes testnet IDs which
mismatch when STELLAR_NETWORK/NEXT_PUBLIC_STELLAR_NETWORK='public'; update
CONTRACT_ADDRESSES to choose defaults based on the network env (e.g. check
process.env.NEXT_PUBLIC_STELLAR_NETWORK or STELLAR_NETWORK) so that each key
(bountyRegistry, coreEscrow, reputationRegistry, projectRegistry) uses mainnet
fallback IDs when network === 'public' and testnet IDs otherwise (or remove
fallbacks and require NEXT_PUBLIC_*_CONTRACT_ID to be set); adjust the constant
CONTRACT_ADDRESSES accordingly so factories that read these values get the
proper network-specific IDs.

In `@lib/contracts/project-registry/package.json`:
- Line 11: Update the dependency entry for "@stellar/stellar-sdk" in
package.json from "^14.5.0" to "^14.6.1" to pull in the Soroban
assembleTransaction bug fix; after editing the "@stellar/stellar-sdk" version
string, run your package manager to update the lockfile (npm install or yarn
install) and run the test suite and any Soroban-related integration checks to
ensure no regressions.

In `@lib/contracts/project-registry/README.md`:
- Around line 43-49: The README example uses non-existent symbols; update it to
import Client (not Contract) from the package and reference the actual exported
networks entry (networks.testnet) — e.g., change the import to use Client and
networks, and instantiate new Client({ ...networks.testnet, rpcUrl: '...' }) so
the example matches the generated API (look for Client and networks.testnet in
lib/contracts/project-registry/src/index.ts).

In `@lib/contracts/reputation-registry/README.md`:
- Line 47: The README example references networks.futurenet while the CLI
example uses testnet—verify the exported network identifiers in src/index.ts
(look for the networks export and names like testnet or futurenet) and update
the README example to use the correct exported symbol (e.g., networks.testnet)
so the example matches the actual export; if the library should expose futurenet
instead, update the export in src/index.ts to include networks.futurenet and
ensure the README and CLI samples are consistent.

In `@lib/contracts/reputation-registry/tsconfig.json`:
- Line 47: The project compiles reputation-registry into "./dist" (tsconfig.json
outDir) but consumers import the source path ("./reputation-registry/src/index")
from lib/contracts/index.ts so the built output is never used; either update the
consumer import to reference the compiled output or stop emitting a separate
dist. Fix by changing the import in lib/contracts/index.ts from
"./reputation-registry/src/index" to the compiled entry (e.g.,
"./reputation-registry/dist/index" or "./reputation-registry" if package.json
exports point to dist/index.js), or alternatively update package.json exports to
point to the source and remove/outDir or adjust tsconfig.json to emit to the
path the consumers expect; locate tsconfig.json (outDir), package.json exports,
and the import in lib/contracts/index.ts to make the paths consistent.

In `@lib/contracts/transaction.ts`:
- Around line 24-40: The function buildTransaction currently builds and
simulates a TransactionBuilder result stored in builtTx but returns tx.toXDR(),
so the constructed/simulated transaction is never returned; change the return to
use the built transaction (builtTx.toXDR()) or otherwise convert the actual
built/simulated Transaction object to XDR before returning; update the return
statement in buildTransaction to return builtTx.toXDR() (or assign builtTx back
to tx if you intend to mutate tx) so the sequence number/timeout/simulation are
reflected in the returned XDR.
- Around line 47-72: The submitTransaction helper currently polls
server.getTransaction in submitTransaction with no deadline and only returns the
hash, which can hang indefinitely and discards useful write-method results;
update submitTransaction to accept a configurable timeout/deadline (or use a
fixed maxRetries) and break the polling loop with a clear error when exceeded
(use sendResponse, getResponse, SorobanRpc.Api.GetTransactionStatus.NOT_FOUND
and server.getTransaction to locate the code), and change the return value to
include the original sendResponse and the final getResponse (e.g., return an
object containing hash, sendResponse, and getResponse) so callers of write
methods (create_bounty, create_pool, register_project) can access
contract-returned values instead of just the transaction hash.

---

Nitpick comments:
In @.env.example:
- Around line 34-38: The .env.example currently hardcodes
NEXT_PUBLIC_BOUNTY_REGISTRY_CONTRACT_ID, NEXT_PUBLIC_CORE_ESCROW_CONTRACT_ID,
NEXT_PUBLIC_REPUTATION_REGISTRY_CONTRACT_ID, and
NEXT_PUBLIC_PROJECT_REGISTRY_CONTRACT_ID which duplicate defaults defined in
lib/contracts/index.ts; pick one canonical source for those default contract IDs
(prefer lib/contracts/index.ts as the runtime/default source) and remove the
hardcoded defaults from .env.example (leave placeholder keys or comment
indicating they are defined in lib/contracts/index.ts), or alternatively move
the canonical defaults into .env.example and have lib/contracts/index.ts read
from process.env; update references to NEXT_PUBLIC_* keys accordingly so only
one place holds the truth.
- Line 38: The file ends without a trailing newline causing dotenv lint
warnings; edit .env.example so the final line (the declaration
NEXT_PUBLIC_PROJECT_REGISTRY_CONTRACT_ID="CCG4QM2GZKBN7GBRAE3PFNE3GM2B6QRS7FOKLHGV2FT2HHETIS7JUVYT")
is followed by a single trailing newline (i.e., an empty line at EOF) and commit
that change.

In `@lib/contracts/bounty-registry/.gitignore`:
- Around line 1-2: Update the package .gitignore to also ignore TypeScript build
artifacts by adding the "dist/" pattern alongside the existing "node_modules/"
and "out/" entries; modify the bounty-registry package .gitignore to include a
new line with "dist/" so compiled output is not committed.

In `@lib/contracts/bounty-registry/package.json`:
- Line 12: The dependency "buffer" in package.json is pinned to an exact version
"6.0.3"; update the version string to a caret range "^6.0.3" so patch/minor
compatible updates are allowed and to reduce dependency resolution
conflicts—edit the "buffer" entry in lib/contracts/bounty-registry/package.json
to use "^6.0.3" instead of "6.0.3".

In `@lib/contracts/bounty-registry/tsconfig.json`:
- Around line 72-74: Enable full TypeScript strict mode by setting the "strict"
compiler option to true (uncomment or add the "strict": true key) instead of
only relying on "strictNullChecks"; keep or remove the individual flags as
needed (TypeScript will derive them from "strict") so update the tsconfig entry
where "strictNullChecks" and the commented "strict" appear to ensure "strict":
true is present and consistent with "strictNullChecks".
- Line 66: Uncomment or add "isolatedModules": true inside the tsconfig's
compilerOptions (the "isolatedModules" flag) so the project is compiled per-file
for bundler compatibility; update the tsconfig.json to set that option to true
and run the type/build tests to ensure no code patterns (e.g., const enums or
non-isolated constructs) need adjusting.

In `@lib/contracts/core-escrow/.gitignore`:
- Around line 1-2: The .gitignore currently lists node_modules/ and out/ but
omits dist/, so add the dist/ entry to the file to ensure build output
(generated JavaScript and declaration files) is not committed; update the file
named core-escrow .gitignore by appending a single line "dist/" (matching the
style of existing entries) so that generated artifacts from package builds are
ignored alongside node_modules/ and out/.

In `@lib/contracts/core-escrow/package.json`:
- Line 12: Update the buffer dependency in package.json from the fixed version
"6.0.3" to a caret range so compatible patch/minor updates are allowed; locate
the "buffer" entry in lib/contracts/core-escrow/package.json and change its
version string to "^6.0.3" (ensuring the JSON remains valid).

In `@lib/contracts/index.ts`:
- Around line 13-14: The central contracts entrypoint currently only re-exports
'./bounty-registry/src/index' and './transaction', so generated bindings for
core escrow, reputation, and project registry remain available only via deep
imports; update lib/contracts/index.ts to also export the generated modules for
those bindings (e.g., add export * from './core-escrow/src/index'; export * from
'./reputation/src/index'; export * from './project-registry/src/index' or
appropriate module names used in the repo) so consumers can import all contract
bindings from this single entrypoint (or alternatively provide namespaced
re-exports if you prefer grouping).

In `@lib/contracts/project-registry/.gitignore`:
- Around line 1-2: Add the compiled output directory to this package's ignore
rules: update the .gitignore in the project-registry package to include "dist/"
(alongside existing entries like "node_modules/" and "out/") so TypeScript build
artifacts are not committed; ensure the entry uses a trailing slash ("dist/") to
clearly ignore the directory.

In `@lib/contracts/project-registry/package.json`:
- Line 12: The package.json currently pins the buffer dependency to an exact
version ("buffer": "6.0.3"); change it to a caret range so npm can install
compatible minor/patch updates by updating the dependency value to "buffer":
"^6.0.3" in the lib/contracts/project-registry package.json (look for the
"buffer" entry in dependencies).

In `@lib/contracts/reputation-registry/.gitignore`:
- Around line 1-2: The .gitignore in the reputation-registry package is missing
the TypeScript build output folder; update the .gitignore (currently containing
"node_modules/" and "out/") to also include "dist/" so generated build artifacts
are ignored; add a new line with dist/ alongside the existing entries in the
same file.

In `@lib/contracts/reputation-registry/tsconfig.json`:
- Around line 72-74: Enable full TypeScript strict mode by setting "strict":
true in tsconfig.json and removing or un-commenting the individual flags (e.g.,
the commented "strict" and "noImplicitAny") so that the compiler enables all
strict checks instead of only "strictNullChecks"; update the config entry that
currently has "strictNullChecks": true to either replace it with "strict": true
or add "strict": true alongside it to ensure flags like noImplicitAny,
strictFunctionTypes, strictBindCallApply, etc. are active.
- Line 66: Enable the TypeScript "isolatedModules" option in the tsconfig by
uncommenting and setting "isolatedModules": true so each file can be transpiled
independently for better bundler compatibility; locate the "isolatedModules"
entry in tsconfig.json (the line currently commented as // "isolatedModules":
true) and restore it as an active compiler option.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e9df28ce-5e14-4559-a0d5-33e068969213

📥 Commits

Reviewing files that changed from the base of the PR and between f7b2708 and e427857.

📒 Files selected for processing (23)
  • .env.example
  • lib/contracts/bounty-registry/.gitignore
  • lib/contracts/bounty-registry/README.md
  • lib/contracts/bounty-registry/package.json
  • lib/contracts/bounty-registry/src/index.ts
  • lib/contracts/bounty-registry/tsconfig.json
  • lib/contracts/core-escrow/.gitignore
  • lib/contracts/core-escrow/README.md
  • lib/contracts/core-escrow/package.json
  • lib/contracts/core-escrow/src/index.ts
  • lib/contracts/core-escrow/tsconfig.json
  • lib/contracts/index.ts
  • lib/contracts/project-registry/.gitignore
  • lib/contracts/project-registry/README.md
  • lib/contracts/project-registry/package.json
  • lib/contracts/project-registry/src/index.ts
  • lib/contracts/project-registry/tsconfig.json
  • lib/contracts/reputation-registry/.gitignore
  • lib/contracts/reputation-registry/README.md
  • lib/contracts/reputation-registry/package.json
  • lib/contracts/reputation-registry/src/index.ts
  • lib/contracts/reputation-registry/tsconfig.json
  • lib/contracts/transaction.ts

- Fix buildTransaction to simulate AssembledTransaction and return its XDR
- Add timeout/deadline to submitTransaction polling loop
- Return { hash, getResponse } from submitTransaction for access to results
- Fix CONTRACT_ADDRESSES to throw on mainnet when env var is not set
- Add namespaced re-exports for core-escrow, reputation, project registries
- Update all READMEs: futurenet → testnet, fix Contract → Client in project-registry
- Add dist/ to .gitignore in each contract package
- Update @stellar/stellar-sdk to ^14.6.1 in contract package.json files
- Change buffer pin 6.0.3 → ^6.0.3 in contract package.json files
- Enable strict mode and isolatedModules in contract tsconfig.json files
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
lib/contracts/index.ts (2)

24-32: Consider using stricter types for network configuration maps.

Using Record<string, string> allows arbitrary keys, but these maps are only ever accessed with 'testnet' or 'public'.

♻️ Optional: Use literal union type
-const RPC_URLS: Record<string, string> = {
+type StellarNetwork = 'testnet' | 'public';
+
+const RPC_URLS: Record<StellarNetwork, string> = {
   testnet: 'https://soroban-testnet.stellar.org',
   public: 'https://mainnet.sorobanrpc.com',
 };

-const NETWORK_PASSPHRASES: Record<string, string> = {
+const NETWORK_PASSPHRASES: Record<StellarNetwork, string> = {
   testnet: 'Test SDF Network ; September 2015',
   public: 'Public Global Stellar Network ; September 2015',
 };
+
+const STELLAR_NETWORK: StellarNetwork = ...
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/index.ts` around lines 24 - 32, RPC_URLS and
NETWORK_PASSPHRASES are typed as Record<string,string>, allowing arbitrary keys;
tighten their types by introducing a union type (e.g., Network = 'testnet' |
'public') and change both declarations to use Record<Network,string> or directly
type them as { testnet: string; public: string } (or mark them as const with
that literal type) so only 'testnet' and 'public' keys are accepted; update any
usages of RPC_URLS or NETWORK_PASSPHRASES accordingly to satisfy the new type.

78-84: Consider using const arrow functions per coding guidelines.

Multiple function declarations could be converted to const arrow functions for consistency with coding guidelines.

♻️ Optional: Convert to arrow functions
-export function getRpcUrl(): string {
-  return RPC_URLS[STELLAR_NETWORK];
-}
+export const getRpcUrl = (): string => RPC_URLS[STELLAR_NETWORK];

-export function getNetworkPassphrase(): string {
-  return NETWORK_PASSPHRASES[STELLAR_NETWORK];
-}
+export const getNetworkPassphrase = (): string => NETWORK_PASSPHRASES[STELLAR_NETWORK];

-function baseClientOptions(contractId: string): ContractClientOptions {
+const baseClientOptions = (contractId: string): ContractClientOptions => ({
-  return {
-    contractId,
-    networkPassphrase: getNetworkPassphrase(),
-    rpcUrl: getRpcUrl(),
-  };
-}
+  contractId,
+  networkPassphrase: getNetworkPassphrase(),
+  rpcUrl: getRpcUrl(),
+});

-export function createBountyRegistryClient(
-  publicKey?: string
-): BountyRegistryClient {
+export const createBountyRegistryClient = (
+  publicKey?: string
+): BountyRegistryClient => {
   return new BountyRegistryClient({
     ...baseClientOptions(CONTRACT_ADDRESSES.bountyRegistry),
     ...(publicKey ? { publicKey } : {}),
   });
-}
+};

Apply similar pattern to the other factory functions.

As per coding guidelines: "Prefer const arrow functions with explicit type annotations over function declarations".

Also applies to: 86-92, 100-107, 113-118, 124-131, 137-144

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/index.ts` around lines 78 - 84, Replace the function
declarations getRpcUrl and getNetworkPassphrase with const arrow functions that
include explicit return type annotations (e.g., const getRpcUrl = (): string =>
RPC_URLS[STELLAR_NETWORK]; and const getNetworkPassphrase = (): string =>
NETWORK_PASSPHRASES[STELLAR_NETWORK];) and apply the same conversion pattern to
the other factory functions in this module so all follow the "const arrow
function with explicit type" guideline.
lib/contracts/transaction.ts (1)

9-14: Consider using const arrow functions per coding guidelines.

The guidelines prefer const arrow functions with explicit type annotations over function declarations.

♻️ Optional refactor to arrow functions
-export async function simulateContract<T>(
-  tx: AssembledTransaction<T>
-): Promise<T> {
+export const simulateContract = async <T>(
+  tx: AssembledTransaction<T>
+): Promise<T> => {
   await tx.simulate();
   return tx.result;
-}
+};

-export async function buildTransaction<T>(
-  tx: AssembledTransaction<T>
-): Promise<string> {
+export const buildTransaction = async <T>(
+  tx: AssembledTransaction<T>
+): Promise<string> => {
   await tx.simulate();
   return tx.toXDR();
-}
+};

-export async function submitTransaction(
-  signedXdr: string,
-  maxWaitSeconds = 30
-): Promise<SubmitTransactionResult> {
+export const submitTransaction = async (
+  signedXdr: string,
+  maxWaitSeconds = 30
+): Promise<SubmitTransactionResult> => {

As per coding guidelines: "Prefer const arrow functions with explicit type annotations over function declarations".

Also applies to: 21-26, 39-42

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/transaction.ts` around lines 9 - 14, Change the exported
function declaration simulateContract to a const arrow function with an explicit
type annotation (e.g., export const simulateContract: <T>(tx:
AssembledTransaction<T>) => Promise<T> = async (tx) => { ... }) and return
tx.result as before; apply the same refactor to the other exported functions in
this file that use function declarations (the other occurrences mentioned in the
review) so they follow the coding guideline of const arrow functions with
explicit types. Ensure names (simulateContract and the other exported functions)
and their generic/type signatures remain identical and preserve existing
behavior and exports.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/contracts/index.ts`:
- Around line 21-22: The STELLAR_NETWORK resolution in lib/contracts/index.ts
currently treats any non-'public' value (including 'mainnet') as 'testnet';
update the logic that sets the STELLAR_NETWORK constant so it treats 'mainnet'
as a synonym for 'public' (matching the pattern in lib/wallet-utils.ts) — e.g.,
normalize process.env.NEXT_PUBLIC_STELLAR_NETWORK and check for both 'public'
and 'mainnet' (or map 'mainnet' → 'public') before falling back to 'testnet', so
functions/classes that use STELLAR_NETWORK get the intended network.

---

Nitpick comments:
In `@lib/contracts/index.ts`:
- Around line 24-32: RPC_URLS and NETWORK_PASSPHRASES are typed as
Record<string,string>, allowing arbitrary keys; tighten their types by
introducing a union type (e.g., Network = 'testnet' | 'public') and change both
declarations to use Record<Network,string> or directly type them as { testnet:
string; public: string } (or mark them as const with that literal type) so only
'testnet' and 'public' keys are accepted; update any usages of RPC_URLS or
NETWORK_PASSPHRASES accordingly to satisfy the new type.
- Around line 78-84: Replace the function declarations getRpcUrl and
getNetworkPassphrase with const arrow functions that include explicit return
type annotations (e.g., const getRpcUrl = (): string =>
RPC_URLS[STELLAR_NETWORK]; and const getNetworkPassphrase = (): string =>
NETWORK_PASSPHRASES[STELLAR_NETWORK];) and apply the same conversion pattern to
the other factory functions in this module so all follow the "const arrow
function with explicit type" guideline.

In `@lib/contracts/transaction.ts`:
- Around line 9-14: Change the exported function declaration simulateContract to
a const arrow function with an explicit type annotation (e.g., export const
simulateContract: <T>(tx: AssembledTransaction<T>) => Promise<T> = async (tx) =>
{ ... }) and return tx.result as before; apply the same refactor to the other
exported functions in this file that use function declarations (the other
occurrences mentioned in the review) so they follow the coding guideline of
const arrow functions with explicit types. Ensure names (simulateContract and
the other exported functions) and their generic/type signatures remain identical
and preserve existing behavior and exports.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 269a5ee4-04f3-49c2-aa5e-fd9fbf733d13

📥 Commits

Reviewing files that changed from the base of the PR and between e427857 and 0fbed03.

📒 Files selected for processing (18)
  • lib/contracts/bounty-registry/.gitignore
  • lib/contracts/bounty-registry/README.md
  • lib/contracts/bounty-registry/package.json
  • lib/contracts/bounty-registry/tsconfig.json
  • lib/contracts/core-escrow/.gitignore
  • lib/contracts/core-escrow/README.md
  • lib/contracts/core-escrow/package.json
  • lib/contracts/core-escrow/tsconfig.json
  • lib/contracts/index.ts
  • lib/contracts/project-registry/.gitignore
  • lib/contracts/project-registry/README.md
  • lib/contracts/project-registry/package.json
  • lib/contracts/project-registry/tsconfig.json
  • lib/contracts/reputation-registry/.gitignore
  • lib/contracts/reputation-registry/README.md
  • lib/contracts/reputation-registry/package.json
  • lib/contracts/reputation-registry/tsconfig.json
  • lib/contracts/transaction.ts
✅ Files skipped from review due to trivial changes (14)
  • lib/contracts/bounty-registry/.gitignore
  • lib/contracts/core-escrow/.gitignore
  • lib/contracts/project-registry/.gitignore
  • lib/contracts/reputation-registry/.gitignore
  • lib/contracts/core-escrow/tsconfig.json
  • lib/contracts/reputation-registry/package.json
  • lib/contracts/project-registry/README.md
  • lib/contracts/bounty-registry/README.md
  • lib/contracts/reputation-registry/tsconfig.json
  • lib/contracts/core-escrow/package.json
  • lib/contracts/bounty-registry/tsconfig.json
  • lib/contracts/reputation-registry/README.md
  • lib/contracts/core-escrow/README.md
  • lib/contracts/project-registry/tsconfig.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/contracts/project-registry/package.json
  • lib/contracts/bounty-registry/package.json

Comment on lines +21 to +22
const STELLAR_NETWORK =
process.env.NEXT_PUBLIC_STELLAR_NETWORK === 'public' ? 'public' : 'testnet';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

'mainnet' is not recognized as a valid network value.

Unlike lib/wallet-utils.ts which handles 'mainnet' as a synonym for 'public', this file's network resolution silently falls back to 'testnet' if someone sets NEXT_PUBLIC_STELLAR_NETWORK='mainnet'. This could cause unexpected testnet behavior when mainnet was intended.

🔧 Proposed fix to align with wallet-utils.ts pattern
-const STELLAR_NETWORK =
-  process.env.NEXT_PUBLIC_STELLAR_NETWORK === 'public' ? 'public' : 'testnet';
+const rawNetwork = process.env.NEXT_PUBLIC_STELLAR_NETWORK || 'testnet';
+const STELLAR_NETWORK =
+  rawNetwork === 'public' || rawNetwork === 'mainnet' ? 'public' : 'testnet';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/contracts/index.ts` around lines 21 - 22, The STELLAR_NETWORK resolution
in lib/contracts/index.ts currently treats any non-'public' value (including
'mainnet') as 'testnet'; update the logic that sets the STELLAR_NETWORK constant
so it treats 'mainnet' as a synonym for 'public' (matching the pattern in
lib/wallet-utils.ts) — e.g., normalize process.env.NEXT_PUBLIC_STELLAR_NETWORK
and check for both 'public' and 'mainnet' (or map 'mainnet' → 'public') before
falling back to 'testnet', so functions/classes that use STELLAR_NETWORK get the
intended network.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Milestone Submission Flow as per Figma Design

1 participant